Skip to content

Commit

Permalink
feat: add OpenApi spec to feature variants (#1659)
Browse files Browse the repository at this point in the history
* feat: add OpenApi spec to feature variants
  • Loading branch information
Christopher Kolstad committed Jun 3, 2022
1 parent 05b65c5 commit 7895002
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 9 deletions.
12 changes: 12 additions & 0 deletions src/lib/openapi/spec/feature-variants-response.ts
@@ -0,0 +1,12 @@
import { OpenAPIV3 } from 'openapi-types';

export const featureVariantsResponse: OpenAPIV3.ResponseObject = {
description: 'featureVariantResponse',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/featureVariantsSchema',
},
},
},
};
26 changes: 26 additions & 0 deletions src/lib/openapi/spec/feature-variants-schema.ts
@@ -0,0 +1,26 @@
import { createSchemaObject, CreateSchemaType } from '../types';
import { variantSchema } from './variant-schema';

const schema = {
type: 'object',
additionalProperties: false,
required: ['version', 'variants'],
properties: {
version: {
type: 'integer',
},
variants: {
type: 'array',
items: {
$ref: '#/components/schemas/variantSchema',
},
},
},
'components/schemas': {
variantSchema,
},
};

export type FeatureVariantsSchema = CreateSchemaType<typeof schema>;

export const featureVariantsSchema = createSchemaObject(schema);
15 changes: 15 additions & 0 deletions src/lib/openapi/spec/update-feature-variants-request.ts
@@ -0,0 +1,15 @@
import { OpenAPIV3 } from 'openapi-types';

export const updateFeatureVariantsRequest: OpenAPIV3.RequestBodyObject = {
required: true,
content: {
'application/json': {
schema: {
type: 'array',
items: {
$ref: '#/components/schemas/variantSchema',
},
},
},
},
};
61 changes: 52 additions & 9 deletions src/lib/routes/admin-api/project/variants.ts
Expand Up @@ -5,10 +5,14 @@ import { IUnleashConfig } from '../../../types/option';
import { IUnleashServices } from '../../../types';
import { Request, Response } from 'express';
import { Operation } from 'fast-json-patch';
import { UPDATE_FEATURE_VARIANTS } from '../../../types/permissions';
import { NONE, UPDATE_FEATURE_VARIANTS } from '../../../types/permissions';
import { IVariant } from '../../../types/model';
import { extractUsername } from '../../../util/extract-user';
import { IAuthRequest } from '../../unleash-types';
import { featureVariantsResponse } from '../../../openapi/spec/feature-variants-response';
import { patchRequest } from '../../../openapi/spec/patch-request';
import { updateFeatureVariantsRequest } from '../../../openapi/spec/update-feature-variants-request';
import { FeatureVariantsSchema } from '../../../openapi/spec/feature-variants-schema';

const PREFIX = '/:projectId/features/:featureName/variants';

Expand All @@ -19,7 +23,6 @@ interface FeatureParams extends ProjectParam {
interface ProjectParam {
projectId: string;
}

export default class VariantsController extends Controller {
private logger: Logger;

Expand All @@ -29,19 +32,59 @@ export default class VariantsController extends Controller {
config: IUnleashConfig,
{
featureToggleService,
}: Pick<IUnleashServices, 'featureToggleService'>,
openApiService,
}: Pick<IUnleashServices, 'featureToggleService' | 'openApiService'>,
) {
super(config);
this.logger = config.getLogger('admin-api/project/variants.ts');
this.featureService = featureToggleService;
this.get(PREFIX, this.getVariants);
this.patch(PREFIX, this.patchVariants, UPDATE_FEATURE_VARIANTS);
this.put(PREFIX, this.overwriteVariants, UPDATE_FEATURE_VARIANTS);
this.route({
method: 'get',
path: PREFIX,
permission: NONE,
acceptAnyContentType: true,
handler: this.getVariants,
middleware: [
openApiService.validPath({
tags: ['admin'],
operationId: 'getFeatureVariants',
responses: { 200: featureVariantsResponse },
}),
],
});
this.route({
method: 'patch',
path: PREFIX,
permission: UPDATE_FEATURE_VARIANTS,
handler: this.patchVariants,
middleware: [
openApiService.validPath({
tags: ['admin'],
operationId: 'patchFeatureVariants',
requestBody: patchRequest,
responses: { 200: featureVariantsResponse },
}),
],
});
this.route({
method: 'put',
path: PREFIX,
permission: UPDATE_FEATURE_VARIANTS,
handler: this.overwriteVariants,
middleware: [
openApiService.validPath({
tags: ['admin'],
operationId: 'overwriteFeatureVariants',
requestBody: updateFeatureVariantsRequest,
responses: { 200: featureVariantsResponse },
}),
],
});
}

async getVariants(
req: Request<FeatureParams, any, any, any>,
res: Response,
res: Response<FeatureVariantsSchema>,
): Promise<void> {
const { featureName } = req.params;
const variants = await this.featureService.getVariants(featureName);
Expand All @@ -50,7 +93,7 @@ export default class VariantsController extends Controller {

async patchVariants(
req: IAuthRequest<FeatureParams, any, Operation[]>,
res: Response,
res: Response<FeatureVariantsSchema>,
): Promise<void> {
const { projectId, featureName } = req.params;
const userName = extractUsername(req);
Expand All @@ -69,7 +112,7 @@ export default class VariantsController extends Controller {

async overwriteVariants(
req: IAuthRequest<FeatureParams, any, IVariant[], any>,
res: Response,
res: Response<FeatureVariantsSchema>,
): Promise<void> {
const { projectId, featureName } = req.params;
const userName = extractUsername(req);
Expand Down
1 change: 1 addition & 0 deletions src/test/e2e/api/admin/project/variants.e2e.test.ts
Expand Up @@ -266,6 +266,7 @@ test('PUTing an invalid variant throws 400 exception', async () => {
name: 'variant',
weight: 500,
weightType: 'party',
stickiness: 'userId',
},
];
await app.request
Expand Down
136 changes: 136 additions & 0 deletions src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap
Expand Up @@ -1515,6 +1515,142 @@ Object {
],
},
},
"/api/admin/projects/{projectId}/features/{featureName}/variants": Object {
"get": Object {
"operationId": "getFeatureVariants",
"parameters": Array [
Object {
"in": "path",
"name": "projectId",
"required": true,
"schema": Object {
"type": "string",
},
},
Object {
"in": "path",
"name": "featureName",
"required": true,
"schema": Object {
"type": "string",
},
},
],
"responses": Object {
"200": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"$ref": "#/components/schemas/featureVariantsSchema",
},
},
},
"description": "featureVariantResponse",
},
},
"tags": Array [
"admin",
],
},
"patch": Object {
"operationId": "patchFeatureVariants",
"parameters": Array [
Object {
"in": "path",
"name": "projectId",
"required": true,
"schema": Object {
"type": "string",
},
},
Object {
"in": "path",
"name": "featureName",
"required": true,
"schema": Object {
"type": "string",
},
},
],
"requestBody": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"items": Object {
"$ref": "#/components/schemas/patchOperationSchema",
},
"type": "array",
},
},
},
"required": true,
},
"responses": Object {
"200": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"$ref": "#/components/schemas/featureVariantsSchema",
},
},
},
"description": "featureVariantResponse",
},
},
"tags": Array [
"admin",
],
},
"put": Object {
"operationId": "overwriteFeatureVariants",
"parameters": Array [
Object {
"in": "path",
"name": "projectId",
"required": true,
"schema": Object {
"type": "string",
},
},
Object {
"in": "path",
"name": "featureName",
"required": true,
"schema": Object {
"type": "string",
},
},
],
"requestBody": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"items": Object {
"$ref": "#/components/schemas/variantSchema",
},
"type": "array",
},
},
},
"required": true,
},
"responses": Object {
"200": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"$ref": "#/components/schemas/featureVariantsSchema",
},
},
},
"description": "featureVariantResponse",
},
},
"tags": Array [
"admin",
],
},
},
},
"security": Array [
Object {
Expand Down

0 comments on commit 7895002

Please sign in to comment.