From 19ec66a9d17d753712fdc28af6188c216b422246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Fournier?= Date: Mon, 4 Sep 2023 16:02:24 +0200 Subject: [PATCH] chore: token api simplification (#4600) ## About the changes We found a problem generating the Go SDK client for the tokens API that makes use of `oneOf`, combined with `allOf`. The generator doesn't know how to map this type and leaves it as an object. This PR simplifies the spec and therefore the code generated after it --- .../openapi/spec/create-api-token-schema.ts | 38 ++++++++-------- src/lib/openapi/util/all-of.ts | 43 +++++++++++++++++++ 2 files changed, 60 insertions(+), 21 deletions(-) create mode 100644 src/lib/openapi/util/all-of.ts diff --git a/src/lib/openapi/spec/create-api-token-schema.ts b/src/lib/openapi/spec/create-api-token-schema.ts index 150c06d4c3d6..8a69e04aa954 100644 --- a/src/lib/openapi/spec/create-api-token-schema.ts +++ b/src/lib/openapi/spec/create-api-token-schema.ts @@ -1,5 +1,5 @@ import { FromSchema } from 'json-schema-to-ts'; - +import { mergeAllOfs } from '../util/all-of'; const adminSchema = { required: ['type'], type: 'object', @@ -74,6 +74,18 @@ const clientFrontendSchema = { }, } as const; +const expireSchema = { + type: 'object', + properties: { + expiresAt: { + type: 'string', + format: 'date-time', + description: 'The time when this token should expire.', + example: '2023-07-04T11:26:24+02:00', + }, + }, +} as const; + // TODO: (openapi) this schema isn't entirely correct: `project` and `projects` // are mutually exclusive. // @@ -88,27 +100,11 @@ export const createApiTokenSchema = { type: 'object', description: 'The data required to create an [Unleash API token](https://docs.getunleash.io/reference/api-tokens-and-client-keys).', - properties: { - expiresAt: { - type: 'string', - format: 'date-time', - description: 'The time when this token should expire.', - example: '2023-07-04T11:26:24+02:00', - }, - }, oneOf: [ - { - allOf: [adminSchema, tokenNameSchema], - }, - { - allOf: [adminSchema, usernameSchema], - }, - { - allOf: [clientFrontendSchema, tokenNameSchema], - }, - { - allOf: [clientFrontendSchema, usernameSchema], - }, + mergeAllOfs([expireSchema, adminSchema, tokenNameSchema]), + mergeAllOfs([expireSchema, adminSchema, usernameSchema]), + mergeAllOfs([expireSchema, clientFrontendSchema, tokenNameSchema]), + mergeAllOfs([expireSchema, clientFrontendSchema, usernameSchema]), ], components: {}, } as const; diff --git a/src/lib/openapi/util/all-of.ts b/src/lib/openapi/util/all-of.ts new file mode 100644 index 000000000000..1e5e82b44953 --- /dev/null +++ b/src/lib/openapi/util/all-of.ts @@ -0,0 +1,43 @@ +import { JSONSchema } from 'json-schema-to-ts'; + +// this function simplifies simple schemas and return allOf schema if it +// doesn't know how to simplify it. It's a proof of concept but it can be extended +export function mergeAllOf(a: JSONSchema, b: JSONSchema): JSONSchema { + if (typeof a !== 'boolean' && typeof b !== 'boolean') { + const { + required: aRequired, + properties: aProperties, + type: aType, + ...aRest + } = a; + const { + required: bRequired, + properties: bProperties, + type: bType, + ...bRest + } = b; + if ( + Object.keys(aRest).length === 0 && + Object.keys(bRest).length === 0 && + aType === 'object' && + bType === 'object' + ) { + return { + required: [...(aRequired ?? []), ...(bRequired ?? [])], + type: 'object', + properties: { ...aProperties, ...bProperties }, + }; + } + } + return { + allOf: [a, b], + }; +} + +export function mergeAllOfs(schemas: JSONSchema[]): JSONSchema { + if (schemas.length === 1) { + return schemas[0]; + } + const [a, b, ...rest] = schemas; + return mergeAllOfs([mergeAllOf(a, b), ...rest]); +}