Skip to content

Commit

Permalink
feat: Frontend api openapi spec (#4133)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew committed Jul 3, 2023
1 parent d3b3652 commit b50b06c
Show file tree
Hide file tree
Showing 4 changed files with 358 additions and 11 deletions.
20 changes: 19 additions & 1 deletion src/lib/openapi/spec/proxy-feature-schema.ts
Expand Up @@ -9,12 +9,19 @@ export const proxyFeatureSchema = {
properties: {
name: {
type: 'string',
example: 'disable-comments',
description: 'Unique feature name.',
},
enabled: {
type: 'boolean',
example: true,
description: 'Always set to `true`.',
},
impressionData: {
type: 'boolean',
example: false,
description:
'`true` if the impression data collection is enabled for the feature, otherwise `false`.',
},
variant: {
type: 'object',
Expand All @@ -23,20 +30,31 @@ export const proxyFeatureSchema = {
properties: {
name: {
type: 'string',
description:
'The variants name. Is unique for this feature toggle',
example: 'blue_group',
},
enabled: {
type: 'boolean',
example: true,
description: 'Whether the variant is enabled or not.',
},
payload: {
type: 'object',
additionalProperties: false,
required: ['type', 'value'],
description: 'Extra data configured for this variant',
example: { type: 'json', value: '{color: red}' },
properties: {
type: {
type: 'string',
description: 'The format of the payload.',
enum: Object.values(PayloadType),
},
value: { type: 'string' },
value: {
type: 'string',
description: 'The payload value stringified.',
},
},
},
},
Expand Down
7 changes: 1 addition & 6 deletions src/lib/routes/index.ts
Expand Up @@ -10,7 +10,6 @@ const ClientApi = require('./client-api');
const Controller = require('./controller');
import { HealthCheckController } from './health-check';
import ProxyController from './proxy-api';
import { conditionalMiddleware } from '../middleware';
import EdgeController from './edge-api';
import { PublicInviteController } from './public-invite';
import { Db } from '../db/db';
Expand Down Expand Up @@ -47,11 +46,7 @@ class IndexRouter extends Controller {

this.use(
'/api/frontend',
conditionalMiddleware(
() => config.flagResolver.isEnabled('embedProxy'),
new ProxyController(config, services, config.flagResolver)
.router,
),
new ProxyController(config, services, config.flagResolver).router,
);

this.use('/edge', new EdgeController(config, services).router);
Expand Down
35 changes: 31 additions & 4 deletions src/lib/routes/proxy-api/index.ts
Expand Up @@ -13,6 +13,7 @@ import {
createRequestSchema,
createResponseSchema,
emptyResponse,
getStandardResponses,
ProxyClientSchema,
proxyFeaturesSchema,
ProxyFeaturesSchema,
Expand All @@ -21,6 +22,7 @@ import { Context } from 'unleash-client';
import { enrichContextWithIp } from '../../proxy';
import { corsOriginMiddleware } from '../../middleware';
import NotImplementedError from '../../error/not-implemented-error';
import NotFoundError from '../../error/notfound-error';

interface ApiUserRequest<
PARAM = any,
Expand Down Expand Up @@ -68,7 +70,12 @@ export default class ProxyController extends Controller {
operationId: 'getFrontendFeatures',
responses: {
200: createResponseSchema('proxyFeaturesSchema'),
...getStandardResponses(401, 404),
},
summary:
'Retrieve enabled feature toggles for the provided context.',
description:
'This endpoint returns the list of feature toggles that the proxy evaluates to enabled for the given context. Context values are provided as query parameters. If the Frontend API is disabled 404 is returned.',
}),
],
});
Expand All @@ -95,24 +102,35 @@ export default class ProxyController extends Controller {
middleware: [
this.services.openApiService.validPath({
tags: ['Frontend API'],
summary: 'Register client usage metrics',
description: `Registers usage metrics. Stores information about how many times each toggle was evaluated to enabled and disabled within a time frame. If provided, this operation will also store data on how many times each feature toggle's variants were displayed to the end user. If the Frontend API is disabled 404 is returned.`,
operationId: 'registerFrontendMetrics',
requestBody: createRequestSchema('clientMetricsSchema'),
responses: { 200: emptyResponse },
responses: {
200: emptyResponse,
...getStandardResponses(400, 401, 404),
},
}),
],
});

this.route({
method: 'post',
path: '/client/register',
handler: ProxyController.registerProxyClient,
handler: this.registerProxyClient,
permission: NONE,
middleware: [
this.services.openApiService.validPath({
tags: ['Frontend API'],
summary: 'Register a client SDK',
description:
'This is for future use. Currently Frontend client registration is not supported. Returning 200 for clients that expect this status code. If the Frontend API is disabled 404 is returned.',
operationId: 'registerFrontendClient',
requestBody: createRequestSchema('proxyClientSchema'),
responses: { 200: emptyResponse },
responses: {
200: emptyResponse,
...getStandardResponses(400, 401, 404),
},
}),
],
});
Expand Down Expand Up @@ -146,6 +164,9 @@ export default class ProxyController extends Controller {
req: ApiUserRequest,
res: Response<ProxyFeaturesSchema>,
) {
if (!this.config.flagResolver.isEnabled('embedProxy')) {
throw new NotFoundError();
}
const toggles = await this.services.proxyService.getProxyFeatures(
req.user,
ProxyController.createContext(req),
Expand All @@ -165,6 +186,9 @@ export default class ProxyController extends Controller {
req: ApiUserRequest<unknown, unknown, ClientMetricsSchema>,
res: Response,
) {
if (!this.config.flagResolver.isEnabled('embedProxy')) {
throw new NotFoundError();
}
await this.services.proxyService.registerProxyMetrics(
req.user,
req.body,
Expand All @@ -173,10 +197,13 @@ export default class ProxyController extends Controller {
res.sendStatus(200);
}

private static async registerProxyClient(
private async registerProxyClient(
req: ApiUserRequest<unknown, unknown, ProxyClientSchema>,
res: Response<string>,
) {
if (!this.config.flagResolver.isEnabled('embedProxy')) {
throw new NotFoundError();
}
// Client registration is not yet supported by @unleash/proxy,
// but proxy clients may still expect a 200 from this endpoint.
res.sendStatus(200);
Expand Down

0 comments on commit b50b06c

Please sign in to comment.