1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: add OpenApi spec to feature variants (#1659)

* feat: add OpenApi spec to feature variants
This commit is contained in:
Christopher Kolstad 2022-06-03 13:16:59 +02:00 committed by GitHub
parent 05b65c53ee
commit 7895002602
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 242 additions and 9 deletions

View File

@ -0,0 +1,12 @@
import { OpenAPIV3 } from 'openapi-types';
export const featureVariantsResponse: OpenAPIV3.ResponseObject = {
description: 'featureVariantResponse',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/featureVariantsSchema',
},
},
},
};

View File

@ -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);

View File

@ -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',
},
},
},
},
};

View File

@ -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';
@ -19,7 +23,6 @@ interface FeatureParams extends ProjectParam {
interface ProjectParam {
projectId: string;
}
export default class VariantsController extends Controller {
private logger: Logger;
@ -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);
@ -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);
@ -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);

View File

@ -266,6 +266,7 @@ test('PUTing an invalid variant throws 400 exception', async () => {
name: 'variant',
weight: 500,
weightType: 'party',
stickiness: 'userId',
},
];
await app.request

View File

@ -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 {