From 4ab8accf5c1778b44f02f961b781d5763898c54c Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Fri, 28 Jul 2023 09:25:34 +0200 Subject: [PATCH] OpenAPI: remaining schema updates (#4354) This fixes the last few exceptions to our meta schema validation --- src/lib/openapi/index.ts | 6 ++- src/lib/openapi/meta-schema-rules.test.ts | 7 +-- .../spec/create-context-field-schema.ts | 21 ++++++++ src/lib/openapi/spec/index.ts | 3 +- src/lib/openapi/spec/patch-schema.ts | 16 ++++++- .../spec/update-context-field-schema.ts | 48 +++++++++++++++++++ .../spec/upsert-context-field-schema.ts | 39 --------------- src/lib/routes/admin-api/context.ts | 18 +++---- 8 files changed, 102 insertions(+), 56 deletions(-) create mode 100644 src/lib/openapi/spec/create-context-field-schema.ts create mode 100644 src/lib/openapi/spec/update-context-field-schema.ts delete mode 100644 src/lib/openapi/spec/upsert-context-field-schema.ts diff --git a/src/lib/openapi/index.ts b/src/lib/openapi/index.ts index 5e8e2af1b3..cbdb86c41a 100644 --- a/src/lib/openapi/index.ts +++ b/src/lib/openapi/index.ts @@ -129,7 +129,8 @@ import { updateFeatureStrategySchema, updateTagTypeSchema, updateUserSchema, - upsertContextFieldSchema, + createContextFieldSchema, + updateContextFieldSchema, upsertSegmentSchema, createStrategySchema, updateStrategySchema, @@ -335,7 +336,8 @@ export const schemas: UnleashSchemas = { updateTagTypeSchema, updateUserSchema, updateTagsSchema, - upsertContextFieldSchema, + createContextFieldSchema, + updateContextFieldSchema, upsertSegmentSchema, createStrategySchema, updateStrategySchema, diff --git a/src/lib/openapi/meta-schema-rules.test.ts b/src/lib/openapi/meta-schema-rules.test.ts index a4e13056d2..cdb006766f 100644 --- a/src/lib/openapi/meta-schema-rules.test.ts +++ b/src/lib/openapi/meta-schema-rules.test.ts @@ -89,10 +89,7 @@ const metaRules: Rule[] = [ }, }, }, - knownExceptions: [ - 'patchSchema', - 'upsertContextFieldSchema', // must be split. Name can't be updated - ], + knownExceptions: [], }, { name: 'should have a description', @@ -103,7 +100,7 @@ const metaRules: Rule[] = [ }, required: ['description'], }, - knownExceptions: ['patchSchema'], + knownExceptions: [], }, ]; diff --git a/src/lib/openapi/spec/create-context-field-schema.ts b/src/lib/openapi/spec/create-context-field-schema.ts new file mode 100644 index 0000000000..044bdc508c --- /dev/null +++ b/src/lib/openapi/spec/create-context-field-schema.ts @@ -0,0 +1,21 @@ +import { FromSchema } from 'json-schema-to-ts'; +import { updateContextFieldSchema } from './update-context-field-schema'; + +export const createContextFieldSchema = { + ...updateContextFieldSchema, + $id: '#/components/schemas/createContextFieldSchema', + description: 'Data used to create a context field configuration.', + required: ['name'], + properties: { + ...updateContextFieldSchema.properties, + name: { + description: 'The name of the context field.', + type: 'string', + example: 'subscriptionTier', + }, + }, +} as const; + +export type CreateContextFieldSchema = FromSchema< + typeof createContextFieldSchema +>; diff --git a/src/lib/openapi/spec/index.ts b/src/lib/openapi/spec/index.ts index 93a67bcedc..711a632ba3 100644 --- a/src/lib/openapi/spec/index.ts +++ b/src/lib/openapi/spec/index.ts @@ -115,7 +115,8 @@ export * from './public-signup-token-schema'; export * from './environments-project-schema'; export * from './instance-admin-stats-schema'; export * from './public-signup-tokens-schema'; -export * from './upsert-context-field-schema'; +export * from './update-context-field-schema'; +export * from './create-context-field-schema'; export * from './validated-edge-tokens-schema'; export * from './client-features-query-schema'; export * from './admin-features-query-schema'; diff --git a/src/lib/openapi/spec/patch-schema.ts b/src/lib/openapi/spec/patch-schema.ts index c8ba1e99e3..9edf08cfe6 100644 --- a/src/lib/openapi/spec/patch-schema.ts +++ b/src/lib/openapi/spec/patch-schema.ts @@ -4,18 +4,32 @@ export const patchSchema = { $id: '#/components/schemas/patchSchema', type: 'object', required: ['path', 'op'], + description: + 'A [JSON patch](https://www.rfc-editor.org/rfc/rfc6902) operation description', properties: { path: { type: 'string', + description: 'The path to the property to operate on', + example: '/type', }, op: { type: 'string', enum: ['add', 'remove', 'replace', 'copy', 'move'], + description: 'The kind of operation to perform', + example: 'replace', }, from: { type: 'string', + description: + 'The target to move or copy from, if performing one of those operations', + example: '/type', + }, + value: { + description: + 'The value to add or replace, if performing one of those operations', + example: 'kill-switch', + nullable: true, }, - value: {}, }, components: {}, } as const; diff --git a/src/lib/openapi/spec/update-context-field-schema.ts b/src/lib/openapi/spec/update-context-field-schema.ts new file mode 100644 index 0000000000..39eae2bdd2 --- /dev/null +++ b/src/lib/openapi/spec/update-context-field-schema.ts @@ -0,0 +1,48 @@ +import { FromSchema } from 'json-schema-to-ts'; +import { legalValueSchema } from './legal-value-schema'; + +export const updateContextFieldSchema = { + $id: '#/components/schemas/updateContextFieldSchema', + type: 'object', + description: 'Data to update an existing context field configuration.', + properties: { + description: { + type: 'string', + description: 'A description of the context field', + example: "The user's subscription tier", + }, + stickiness: { + type: 'boolean', + description: + '`true` if this field should be available for use with [custom stickiness](https://docs.getunleash.io/reference/stickiness#custom-stickiness), otherwise `false`', + example: false, + }, + sortOrder: { + type: 'integer', + description: + 'How this context field should be sorted if no other sort order is selected', + example: 2, + }, + legalValues: { + type: 'array', + description: 'A list of allowed values for this context field', + example: [ + { value: 'gold' }, + { value: 'silver' }, + { value: 'crystal' }, + ], + items: { + $ref: '#/components/schemas/legalValueSchema', + }, + }, + }, + components: { + schemas: { + legalValueSchema, + }, + }, +} as const; + +export type UpdateContextFieldSchema = FromSchema< + typeof updateContextFieldSchema +>; diff --git a/src/lib/openapi/spec/upsert-context-field-schema.ts b/src/lib/openapi/spec/upsert-context-field-schema.ts deleted file mode 100644 index 787ec0a738..0000000000 --- a/src/lib/openapi/spec/upsert-context-field-schema.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { FromSchema } from 'json-schema-to-ts'; -import { legalValueSchema } from './legal-value-schema'; - -export const upsertContextFieldSchema = { - $id: '#/components/schemas/upsertContextFieldSchema', - type: 'object', - description: 'Data to create or update a context field configuration.', - required: ['name'], - properties: { - name: { - description: 'The name of the context field.', - type: 'string', - }, - description: { - type: 'string', - }, - stickiness: { - type: 'boolean', - }, - sortOrder: { - type: 'number', - }, - legalValues: { - type: 'array', - items: { - $ref: '#/components/schemas/legalValueSchema', - }, - }, - }, - components: { - schemas: { - legalValueSchema, - }, - }, -} as const; - -export type UpsertContextFieldSchema = FromSchema< - typeof upsertContextFieldSchema ->; diff --git a/src/lib/routes/admin-api/context.ts b/src/lib/routes/admin-api/context.ts index dd6ac0cb94..d3508c5812 100644 --- a/src/lib/routes/admin-api/context.ts +++ b/src/lib/routes/admin-api/context.ts @@ -22,7 +22,6 @@ import { ContextFieldSchema, } from '../../openapi/spec/context-field-schema'; import { ContextFieldsSchema } from '../../openapi/spec/context-fields-schema'; -import { UpsertContextFieldSchema } from '../../openapi/spec/upsert-context-field-schema'; import { createRequestSchema } from '../../openapi/util/create-request-schema'; import { createResponseSchema, @@ -39,6 +38,8 @@ import { ContextFieldStrategiesSchema, contextFieldStrategiesSchema, } from '../../openapi/spec/context-field-strategies-schema'; +import { UpdateContextFieldSchema } from 'lib/openapi/spec/update-context-field-schema'; +import { CreateContextFieldSchema } from 'lib/openapi/spec/create-context-field-schema'; interface ContextParam { contextField: string; @@ -136,7 +137,7 @@ export class ContextController extends Controller { description: 'Endpoint that allows creation of [custom context fields](https://docs.getunleash.io/reference/unleash-context#custom-context-fields)', requestBody: createRequestSchema( - 'upsertContextFieldSchema', + 'createContextFieldSchema', ), responses: { 201: resourceCreatedResponseSchema( @@ -159,7 +160,7 @@ export class ContextController extends Controller { description: `Endpoint that allows updating a custom context field. Used to toggle stickiness and add/remove legal values for this context field`, operationId: 'updateContextField', requestBody: createRequestSchema( - 'upsertContextFieldSchema', + 'updateContextFieldSchema', ), responses: { 200: emptyResponse, @@ -239,7 +240,7 @@ export class ContextController extends Controller { } async createContextField( - req: IAuthRequest, + req: IAuthRequest, res: Response, ): Promise { const value = req.body; @@ -260,16 +261,17 @@ export class ContextController extends Controller { } async updateContextField( - req: IAuthRequest, + req: IAuthRequest, res: Response, ): Promise { const name = req.params.contextField; const userName = extractUsername(req); const contextField = req.body; - contextField.name = name; - - await this.contextService.updateContextField(contextField, userName); + await this.contextService.updateContextField( + { ...contextField, name }, + userName, + ); res.status(200).end(); }