mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: add OpenApi spec to feature variants (#1659)
* feat: add OpenApi spec to feature variants
This commit is contained in:
		
							parent
							
								
									05b65c53ee
								
							
						
					
					
						commit
						7895002602
					
				
							
								
								
									
										12
									
								
								src/lib/openapi/spec/feature-variants-response.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/lib/openapi/spec/feature-variants-response.ts
									
									
									
									
									
										Normal 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',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/lib/openapi/spec/feature-variants-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/lib/openapi/spec/feature-variants-schema.ts
									
									
									
									
									
										Normal 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);
 | 
				
			||||||
							
								
								
									
										15
									
								
								src/lib/openapi/spec/update-feature-variants-request.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/lib/openapi/spec/update-feature-variants-request.ts
									
									
									
									
									
										Normal 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',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -5,10 +5,14 @@ import { IUnleashConfig } from '../../../types/option';
 | 
				
			|||||||
import { IUnleashServices } from '../../../types';
 | 
					import { IUnleashServices } from '../../../types';
 | 
				
			||||||
import { Request, Response } from 'express';
 | 
					import { Request, Response } from 'express';
 | 
				
			||||||
import { Operation } from 'fast-json-patch';
 | 
					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 { IVariant } from '../../../types/model';
 | 
				
			||||||
import { extractUsername } from '../../../util/extract-user';
 | 
					import { extractUsername } from '../../../util/extract-user';
 | 
				
			||||||
import { IAuthRequest } from '../../unleash-types';
 | 
					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';
 | 
					const PREFIX = '/:projectId/features/:featureName/variants';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -19,7 +23,6 @@ interface FeatureParams extends ProjectParam {
 | 
				
			|||||||
interface ProjectParam {
 | 
					interface ProjectParam {
 | 
				
			||||||
    projectId: string;
 | 
					    projectId: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
export default class VariantsController extends Controller {
 | 
					export default class VariantsController extends Controller {
 | 
				
			||||||
    private logger: Logger;
 | 
					    private logger: Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -29,19 +32,59 @@ export default class VariantsController extends Controller {
 | 
				
			|||||||
        config: IUnleashConfig,
 | 
					        config: IUnleashConfig,
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            featureToggleService,
 | 
					            featureToggleService,
 | 
				
			||||||
        }: Pick<IUnleashServices, 'featureToggleService'>,
 | 
					            openApiService,
 | 
				
			||||||
 | 
					        }: Pick<IUnleashServices, 'featureToggleService' | 'openApiService'>,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        super(config);
 | 
					        super(config);
 | 
				
			||||||
        this.logger = config.getLogger('admin-api/project/variants.ts');
 | 
					        this.logger = config.getLogger('admin-api/project/variants.ts');
 | 
				
			||||||
        this.featureService = featureToggleService;
 | 
					        this.featureService = featureToggleService;
 | 
				
			||||||
        this.get(PREFIX, this.getVariants);
 | 
					        this.route({
 | 
				
			||||||
        this.patch(PREFIX, this.patchVariants, UPDATE_FEATURE_VARIANTS);
 | 
					            method: 'get',
 | 
				
			||||||
        this.put(PREFIX, this.overwriteVariants, UPDATE_FEATURE_VARIANTS);
 | 
					            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(
 | 
					    async getVariants(
 | 
				
			||||||
        req: Request<FeatureParams, any, any, any>,
 | 
					        req: Request<FeatureParams, any, any, any>,
 | 
				
			||||||
        res: Response,
 | 
					        res: Response<FeatureVariantsSchema>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { featureName } = req.params;
 | 
					        const { featureName } = req.params;
 | 
				
			||||||
        const variants = await this.featureService.getVariants(featureName);
 | 
					        const variants = await this.featureService.getVariants(featureName);
 | 
				
			||||||
@ -50,7 +93,7 @@ export default class VariantsController extends Controller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async patchVariants(
 | 
					    async patchVariants(
 | 
				
			||||||
        req: IAuthRequest<FeatureParams, any, Operation[]>,
 | 
					        req: IAuthRequest<FeatureParams, any, Operation[]>,
 | 
				
			||||||
        res: Response,
 | 
					        res: Response<FeatureVariantsSchema>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { projectId, featureName } = req.params;
 | 
					        const { projectId, featureName } = req.params;
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
@ -69,7 +112,7 @@ export default class VariantsController extends Controller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async overwriteVariants(
 | 
					    async overwriteVariants(
 | 
				
			||||||
        req: IAuthRequest<FeatureParams, any, IVariant[], any>,
 | 
					        req: IAuthRequest<FeatureParams, any, IVariant[], any>,
 | 
				
			||||||
        res: Response,
 | 
					        res: Response<FeatureVariantsSchema>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { projectId, featureName } = req.params;
 | 
					        const { projectId, featureName } = req.params;
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -266,6 +266,7 @@ test('PUTing an invalid variant throws 400 exception', async () => {
 | 
				
			|||||||
            name: 'variant',
 | 
					            name: 'variant',
 | 
				
			||||||
            weight: 500,
 | 
					            weight: 500,
 | 
				
			||||||
            weightType: 'party',
 | 
					            weightType: 'party',
 | 
				
			||||||
 | 
					            stickiness: 'userId',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
    await app.request
 | 
					    await app.request
 | 
				
			||||||
 | 
				
			|||||||
@ -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 [
 | 
					  "security": Array [
 | 
				
			||||||
    Object {
 | 
					    Object {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user