Skip to content

Commit

Permalink
fix: should not yield 404 when serverside SDK tries to register (#85)
Browse files Browse the repository at this point in the history
Co-authored-by: Thomas Heartman <[email protected]>
  • Loading branch information
ivarconr and thomasheartman authored Aug 9, 2022
1 parent c41df56 commit 07c6c66
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 0 deletions.
1 change: 1 addition & 0 deletions example.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const app = createApp({
clientKeys: ['proxy-secret', 'another-proxy-secret', 's1'],
refreshInterval: 1000,
logLevel: 'trace',
enableOAS: true,
expServerSideSdkConfig: {
tokens: ['server'],
},
Expand Down
2 changes: 2 additions & 0 deletions src/openapi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { featureSchema } from './spec/feature-schema';
import { featuresSchema } from './spec/features-schema';
import { lookupTogglesSchema } from './spec/lookup-toggles-schema';
import { registerMetricsSchema } from './spec/register-metrics-schema';
import { registerClientSchema } from './spec/register-client-schema';
import { unleashContextSchema } from './spec/unleash-context-schema';
import { variantSchema } from './spec/variant-schema';

Expand Down Expand Up @@ -53,6 +54,7 @@ export const createOpenApiSchema = (
featuresSchema,
lookupTogglesSchema,
registerMetricsSchema,
registerClientSchema,
unleashContextSchema,
variantSchema,
},
Expand Down
11 changes: 11 additions & 0 deletions src/openapi/spec/register-client-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { OpenAPIV3 } from 'openapi-types';

export const registerClientRequest: OpenAPIV3.RequestBodyObject = {
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/registerClientSchema',
},
},
},
};
50 changes: 50 additions & 0 deletions src/openapi/spec/register-client-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { createSchemaObject, CreateSchemaType } from '../openapi-types';

export const schema = {
type: 'object',
required: ['appName', 'interval', 'started', 'strategies'],
properties: {
appName: {
type: 'string',
description: 'Name of the application using Unleash',
},
instanceId: {
type: 'string',
description:
'Instance id for this application (typically hostname, podId or similar)',
},
sdkVersion: {
type: 'string',
description:
'Optional field that describes the sdk version (name:version)',
},
environment: {
type: 'string',
deprecated: true,
},
interval: {
type: 'number',
description:
'At which interval, in milliseconds, will this client be expected to send metrics',
},
started: {
oneOf: [
{ type: 'string', format: 'date-time' },
{ type: 'number' },
],
description:
'When this client started. Should be reported as ISO8601 time.',
},
strategies: {
type: 'array',
items: {
type: 'string',
},
description: 'List of strategies implemented by this application',
},
},
} as const;

export type RegisterClientSchema = CreateSchemaType<typeof schema>;

export const registerClientSchema = createSchemaObject(schema);
123 changes: 123 additions & 0 deletions src/test/__snapshots__/openapi.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,56 @@ Object {
},
"type": "object",
},
"registerClientSchema": Object {
"properties": Object {
"appName": Object {
"description": "Name of the application using Unleash",
"type": "string",
},
"environment": Object {
"deprecated": true,
"type": "string",
},
"instanceId": Object {
"description": "Instance id for this application (typically hostname, podId or similar)",
"type": "string",
},
"interval": Object {
"description": "At which interval, in milliseconds, will this client be expected to send metrics",
"type": "number",
},
"sdkVersion": Object {
"description": "Optional field that describes the sdk version (name:version)",
"type": "string",
},
"started": Object {
"description": "When this client started. Should be reported as ISO8601 time.",
"oneOf": Array [
Object {
"format": "date-time",
"type": "string",
},
Object {
"type": "number",
},
],
},
"strategies": Object {
"description": "List of strategies implemented by this application",
"items": Object {
"type": "string",
},
"type": "array",
},
},
"required": Array [
"appName",
"interval",
"started",
"strategies",
],
"type": "object",
},
"registerMetricsSchema": Object {
"properties": Object {
"appName": Object {
Expand Down Expand Up @@ -852,6 +902,79 @@ Object {
],
},
},
"/proxy/client/register": Object {
"post": Object {
"description": "This endpoint lets you register application with Unleash. Accepts either one of the proxy's configured \`serverSideTokens\` or one of its \`clientKeys\` for authorization.",
"requestBody": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"$ref": "#/components/schemas/registerClientSchema",
},
},
},
},
"responses": Object {
"200": Object {
"content": Object {
"text/plain": Object {
"schema": Object {
"example": "ok",
"type": "string",
},
},
},
"description": "The request was successful.",
},
"400": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"example": Object {
"error": "Request validation failed",
"validation": Array [
Object {
"dataPath": ".body",
"keyword": "required",
"message": "should have required property 'appName'",
"params": Object {
"missingProperty": "appName",
},
"schemaPath": "#/components/schemas/registerMetricsSchema/required",
},
],
},
"properties": Object {
"error": Object {
"type": "string",
},
"validation": Object {
"items": Object {
"type": "object",
},
"type": "array",
},
},
"required": Array [
"error",
],
"type": "object",
},
},
},
"description": "The provided request data is invalid.",
},
"401": Object {
"description": "Authorization information is missing or invalid.",
},
},
"summary": "Register clients with Unleash.",
"tags": Array [
"Operational",
"Server-side client",
],
},
},
"/proxy/health": Object {
"get": Object {
"description": "Returns a 200 OK if the proxy is ready to receive requests. Otherwise returns a 503 NOT READY.",
Expand Down
38 changes: 38 additions & 0 deletions src/test/unleash-proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,3 +523,41 @@ test('Should return 400 bad request for malformed JSON', async () => {
.expect(400)
.expect('Content-Type', /json/);
});

test('Should register server SDK', async () => {
const toggles = [
{
name: 'test',
enabled: true,
impressionData: true,
},
];
const client = new MockClient(toggles);

const proxySecrets = ['sdf'];
const app = createApp(
{
unleashUrl,
unleashApiToken,
proxySecrets,
expServerSideSdkConfig: { tokens: ['s1'] },
},
client,
);
client.emit('ready');

const res = await request(app)
.post('/proxy/client/register')
.send({
appName: 'test',
instanceId: 'i1',
sdkVersion: 'custom1',
environment: 'prod',
interval: 10000,
started: new Date(),
strategies: ['default'],
})
.set('Authorization', 'sdf');

expect(res.statusCode).toBe(200);
});
30 changes: 30 additions & 0 deletions src/unleash-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import { ApiRequestSchema } from './openapi/spec/api-request-schema';
import { FeaturesSchema } from './openapi/spec/features-schema';
import { lookupTogglesRequest } from './openapi/spec/lookup-toggles-request';
import { registerMetricsRequest } from './openapi/spec/register-metrics-request';
import { registerClientRequest } from './openapi/spec/register-client-request';
import {
createDeepObjectRequestParameters,
createRequestParameters,
} from './openapi/openapi-helpers';
import { RegisterMetricsSchema } from './openapi/spec/register-metrics-schema';
import { LookupTogglesSchema } from './openapi/spec/lookup-toggles-schema';
import { RegisterClientSchema } from './openapi/spec/register-client-schema';

export default class UnleashProxy {
private logger: Logger;
Expand Down Expand Up @@ -139,6 +141,19 @@ export default class UnleashProxy {
this.registerMetrics.bind(this),
);

router.post(
'/client/register',
openApiService.validPath({
requestBody: registerClientRequest,
responses: standardResponses(200, 400, 401),
description:
"This endpoint lets you register application with Unleash. Accepts either one of the proxy's configured `serverSideTokens` or one of its `clientKeys` for authorization.",
summary: 'Register clients with Unleash.',
tags: ['Operational', 'Server-side client'],
}),
this.registerClient.bind(this),
);

router.get(
'/health',
openApiService.validPath({
Expand Down Expand Up @@ -266,6 +281,21 @@ export default class UnleashProxy {
}
}

registerClient(
req: Request<{}, undefined, RegisterClientSchema>,
res: Response<string>,
): void {
const token = req.header(this.clientKeysHeaderName);
const validTokens = [...this.clientKeys, ...this.serverSideTokens];

if (token && validTokens.includes(token)) {
this.logger.debug('Client registration is not supported yet.');
res.sendStatus(200);
} else {
res.sendStatus(401);
}
}

unleashApi(req: Request, res: Response<string | ApiRequestSchema>): void {
const apiToken = req.header(this.clientKeysHeaderName);
if (!this.ready) {
Expand Down

0 comments on commit 07c6c66

Please sign in to comment.