From b99eafc9ccf12fb7530ac8ed5a7f9eec43d101d7 Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Thu, 29 Jun 2023 14:04:48 +0200 Subject: [PATCH] docs: Context api tag (#4117) ### What Added documentation for context fields and endpoints tagged with the "Context" tag. --------- Co-authored-by: Thomas Heartman --- src/lib/openapi/meta-schema-rules.test.ts | 5 --- src/lib/openapi/spec/context-field-schema.ts | 24 +++++++++-- src/lib/openapi/spec/context-fields-schema.ts | 1 + src/lib/openapi/spec/legal-value-schema.ts | 6 +++ src/lib/routes/admin-api/context.ts | 19 +++++++++ src/test/e2e/api/admin/state.e2e.test.ts | 12 +++--- .../__snapshots__/openapi.e2e.test.ts.snap | 40 +++++++++++++++++-- 7 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/lib/openapi/meta-schema-rules.test.ts b/src/lib/openapi/meta-schema-rules.test.ts index 7156be5b50..841311117f 100644 --- a/src/lib/openapi/meta-schema-rules.test.ts +++ b/src/lib/openapi/meta-schema-rules.test.ts @@ -94,7 +94,6 @@ const metaRules: Rule[] = [ 'batchStaleSchema', 'changePasswordSchema', 'cloneFeatureSchema', - 'contextFieldSchema', 'createApiTokenSchema', 'createFeatureSchema', 'createInvitedUserSchema', @@ -119,7 +118,6 @@ const metaRules: Rule[] = [ 'groupsSchema', 'groupUserModelSchema', 'idSchema', - 'legalValueSchema', 'loginSchema', 'maintenanceSchema', 'toggleMaintenanceSchema', @@ -187,8 +185,6 @@ const metaRules: Rule[] = [ 'batchStaleSchema', 'changePasswordSchema', 'cloneFeatureSchema', - 'contextFieldSchema', - 'contextFieldsSchema', 'createApiTokenSchema', 'createFeatureSchema', 'createFeatureStrategySchema', @@ -213,7 +209,6 @@ const metaRules: Rule[] = [ 'groupsSchema', 'groupUserModelSchema', 'idSchema', - 'legalValueSchema', 'loginSchema', 'maintenanceSchema', 'toggleMaintenanceSchema', diff --git a/src/lib/openapi/spec/context-field-schema.ts b/src/lib/openapi/spec/context-field-schema.ts index 79cac839a3..4b04da8ba7 100644 --- a/src/lib/openapi/spec/context-field-schema.ts +++ b/src/lib/openapi/spec/context-field-schema.ts @@ -5,41 +5,59 @@ export const contextFieldSchema = { $id: '#/components/schemas/contextFieldSchema', type: 'object', additionalProperties: false, + description: + 'A representation of a [context field](https://docs.getunleash.io/reference/unleash-context).', required: ['name'], properties: { name: { + description: 'The name of the context field', type: 'string', + example: 'userId', }, description: { + description: 'The description of the context field.', type: 'string', nullable: true, + example: 'Used to uniquely identify users', }, stickiness: { + description: + 'Does this context field support being used for [stickiness](https://docs.getunleash.io/reference/stickiness) calculations', type: 'boolean', + example: true, }, sortOrder: { - type: 'number', + description: + 'Used when sorting a list of context fields. Is also used as a tiebreaker if a list of context fields is sorted alphabetically.', + type: 'integer', + example: 900, }, createdAt: { + description: 'When this context field was created', type: 'string', format: 'date-time', nullable: true, + example: '2023-06-29T10:19:00.000Z', }, usedInFeatures: { - type: 'number', + type: 'integer', description: 'Number of projects where this context field is used in', example: 3, nullable: true, + minimum: 0, }, usedInProjects: { - type: 'number', + type: 'integer', description: 'Number of projects where this context field is used in', example: 2, nullable: true, + minimum: 0, }, legalValues: { + description: + 'Allowed values for this context field schema. Can be used to narrow down accepted input', type: 'array', items: { $ref: '#/components/schemas/legalValueSchema', diff --git a/src/lib/openapi/spec/context-fields-schema.ts b/src/lib/openapi/spec/context-fields-schema.ts index 180996c348..64509afe94 100644 --- a/src/lib/openapi/spec/context-fields-schema.ts +++ b/src/lib/openapi/spec/context-fields-schema.ts @@ -5,6 +5,7 @@ import { legalValueSchema } from './legal-value-schema'; export const contextFieldsSchema = { $id: '#/components/schemas/contextFieldsSchema', type: 'array', + description: 'A list of context fields', items: { $ref: '#/components/schemas/contextFieldSchema', }, diff --git a/src/lib/openapi/spec/legal-value-schema.ts b/src/lib/openapi/spec/legal-value-schema.ts index 8fe2d141ca..4c9885bcb6 100644 --- a/src/lib/openapi/spec/legal-value-schema.ts +++ b/src/lib/openapi/spec/legal-value-schema.ts @@ -4,13 +4,19 @@ export const legalValueSchema = { $id: '#/components/schemas/legalValueSchema', type: 'object', additionalProperties: false, + description: + 'Describes a legal value. Typically used to limit possible values for contextFields or strategy properties', required: ['value'], properties: { value: { + description: 'The valid value', type: 'string', + example: '#c154c1', }, description: { + description: 'Describes this specific legal value', type: 'string', + example: 'Deep fuchsia', }, }, components: {}, diff --git a/src/lib/routes/admin-api/context.ts b/src/lib/routes/admin-api/context.ts index a68ea6126c..572b4d52a2 100644 --- a/src/lib/routes/admin-api/context.ts +++ b/src/lib/routes/admin-api/context.ts @@ -65,6 +65,9 @@ export class ContextController extends Controller { middleware: [ openApiService.validPath({ tags: ['Context'], + summary: 'Gets configured context fields', + description: + 'Returns all configured [Context fields](https://docs.getunleash.io/how-to/how-to-define-custom-context-fields) that have been created.', operationId: 'getContextFields', responses: { 200: createResponseSchema('contextFieldsSchema'), @@ -81,6 +84,9 @@ export class ContextController extends Controller { middleware: [ openApiService.validPath({ tags: ['Context'], + summary: 'Gets context field', + description: + 'Returns specific [context field](https://docs.getunleash.io/reference/unleash-context) identified by the name in the path', operationId: 'getContextField', responses: { 200: createResponseSchema('contextFieldSchema'), @@ -97,6 +103,8 @@ export class ContextController extends Controller { middleware: [ openApiService.validPath({ tags: ['Strategies'], + summary: 'Get strategies using this context field', + description: `Returns all strategies that use the specified context field. Useful when cleaning up context fields: if this list is empty, it's safe to delete the context field.`, operationId: 'getStrategiesByContextField', responses: { 200: createResponseSchema( @@ -116,6 +124,9 @@ export class ContextController extends Controller { openApiService.validPath({ tags: ['Context'], operationId: 'createContextField', + summary: 'Create a context field', + description: + 'Endpoint that allows creation of [custom context fields](https://docs.getunleash.io/reference/unleash-context#custom-context-fields)', requestBody: createRequestSchema( 'upsertContextFieldSchema', ), @@ -136,6 +147,8 @@ export class ContextController extends Controller { middleware: [ openApiService.validPath({ tags: ['Context'], + summary: 'Update an existing context field', + 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', @@ -156,6 +169,9 @@ export class ContextController extends Controller { middleware: [ openApiService.validPath({ tags: ['Context'], + summary: 'Delete an existing context field', + description: + 'Endpoint that allows deletion of a custom context field. Does not validate that context field is not in use, but since context field configuration is stored in a json blob for the strategy, existing strategies are safe.', operationId: 'deleteContextField', responses: { 200: emptyResponse, @@ -172,6 +188,9 @@ export class ContextController extends Controller { middleware: [ openApiService.validPath({ tags: ['Context'], + summary: 'Validate a context field', + description: + 'Check whether the provided data can be used to create a context field. If the data is not valid, ...?', operationId: 'validate', requestBody: createRequestSchema('nameSchema'), responses: { diff --git a/src/test/e2e/api/admin/state.e2e.test.ts b/src/test/e2e/api/admin/state.e2e.test.ts index aa2bbdec26..a544c00d8c 100644 --- a/src/test/e2e/api/admin/state.e2e.test.ts +++ b/src/test/e2e/api/admin/state.e2e.test.ts @@ -429,10 +429,10 @@ test(`should not show environment on feature toggle, when environment is disable .expect(200); const result = body.environments; - const sorted = result.sort((e1, e2) => e1.name[0] < e2.name[0]); - expect(sorted).toHaveLength(2); - expect(sorted[0].name).toBe('development'); - expect(sorted[0].enabled).toBeTruthy(); - expect(sorted[1].name).toBe('production'); - expect(sorted[1].enabled).toBeFalsy(); + let dev = result.find((e) => e.name === 'development'); + expect(dev).toBeTruthy(); + expect(dev.enabled).toBe(true); + let prod = result.find((e) => e.name === 'production'); + expect(prod).toBeTruthy(); + expect(prod.enabled).toBe(false); }); diff --git a/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap b/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap index 69352dc914..5f30693f29 100644 --- a/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap +++ b/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap @@ -1683,42 +1683,56 @@ The provider you choose for your addon dictates what properties the \`parameters }, "contextFieldSchema": { "additionalProperties": false, + "description": "A representation of a [context field](https://docs.getunleash.io/reference/unleash-context).", "properties": { "createdAt": { + "description": "When this context field was created", + "example": "2023-06-29T10:19:00.000Z", "format": "date-time", "nullable": true, "type": "string", }, "description": { + "description": "The description of the context field.", + "example": "Used to uniquely identify users", "nullable": true, "type": "string", }, "legalValues": { + "description": "Allowed values for this context field schema. Can be used to narrow down accepted input", "items": { "$ref": "#/components/schemas/legalValueSchema", }, "type": "array", }, "name": { + "description": "The name of the context field", + "example": "userId", "type": "string", }, "sortOrder": { - "type": "number", + "description": "Used when sorting a list of context fields. Is also used as a tiebreaker if a list of context fields is sorted alphabetically.", + "example": 900, + "type": "integer", }, "stickiness": { + "description": "Does this context field support being used for [stickiness](https://docs.getunleash.io/reference/stickiness) calculations", + "example": true, "type": "boolean", }, "usedInFeatures": { "description": "Number of projects where this context field is used in", "example": 3, + "minimum": 0, "nullable": true, - "type": "number", + "type": "integer", }, "usedInProjects": { "description": "Number of projects where this context field is used in", "example": 2, + "minimum": 0, "nullable": true, - "type": "number", + "type": "integer", }, }, "required": [ @@ -1774,6 +1788,7 @@ The provider you choose for your addon dictates what properties the \`parameters "type": "object", }, "contextFieldsSchema": { + "description": "A list of context fields", "items": { "$ref": "#/components/schemas/contextFieldSchema", }, @@ -3468,11 +3483,16 @@ The provider you choose for your addon dictates what properties the \`parameters }, "legalValueSchema": { "additionalProperties": false, + "description": "Describes a legal value. Typically used to limit possible values for contextFields or strategy properties", "properties": { "description": { + "description": "Describes this specific legal value", + "example": "Deep fuchsia", "type": "string", }, "value": { + "description": "The valid value", + "example": "#c154c1", "type": "string", }, }, @@ -7042,6 +7062,7 @@ Note: passing \`null\` as a value for the description property will set it to an }, "/api/admin/context": { "get": { + "description": "Returns all configured [Context fields](https://docs.getunleash.io/how-to/how-to-define-custom-context-fields) that have been created.", "operationId": "getContextFields", "responses": { "200": { @@ -7055,11 +7076,13 @@ Note: passing \`null\` as a value for the description property will set it to an "description": "contextFieldsSchema", }, }, + "summary": "Gets configured context fields", "tags": [ "Context", ], }, "post": { + "description": "Endpoint that allows creation of [custom context fields](https://docs.getunleash.io/reference/unleash-context#custom-context-fields)", "operationId": "createContextField", "requestBody": { "content": { @@ -7093,6 +7116,7 @@ Note: passing \`null\` as a value for the description property will set it to an }, }, }, + "summary": "Create a context field", "tags": [ "Context", ], @@ -7100,6 +7124,7 @@ Note: passing \`null\` as a value for the description property will set it to an }, "/api/admin/context/validate": { "post": { + "description": "Check whether the provided data can be used to create a context field. If the data is not valid, ...?", "operationId": "validate", "requestBody": { "content": { @@ -7117,6 +7142,7 @@ Note: passing \`null\` as a value for the description property will set it to an "description": "This response has no body.", }, }, + "summary": "Validate a context field", "tags": [ "Context", ], @@ -7124,6 +7150,7 @@ Note: passing \`null\` as a value for the description property will set it to an }, "/api/admin/context/{contextField}": { "delete": { + "description": "Endpoint that allows deletion of a custom context field. Does not validate that context field is not in use, but since context field configuration is stored in a json blob for the strategy, existing strategies are safe.", "operationId": "deleteContextField", "parameters": [ { @@ -7140,11 +7167,13 @@ Note: passing \`null\` as a value for the description property will set it to an "description": "This response has no body.", }, }, + "summary": "Delete an existing context field", "tags": [ "Context", ], }, "get": { + "description": "Returns specific [context field](https://docs.getunleash.io/reference/unleash-context) identified by the name in the path", "operationId": "getContextField", "parameters": [ { @@ -7168,11 +7197,13 @@ Note: passing \`null\` as a value for the description property will set it to an "description": "contextFieldSchema", }, }, + "summary": "Gets context field", "tags": [ "Context", ], }, "put": { + "description": "Endpoint that allows updating a custom context field. Used to toggle stickiness and add/remove legal values for this context field", "operationId": "updateContextField", "parameters": [ { @@ -7200,6 +7231,7 @@ Note: passing \`null\` as a value for the description property will set it to an "description": "This response has no body.", }, }, + "summary": "Update an existing context field", "tags": [ "Context", ], @@ -7207,6 +7239,7 @@ Note: passing \`null\` as a value for the description property will set it to an }, "/api/admin/context/{contextField}/strategies": { "get": { + "description": "Returns all strategies that use the specified context field. Useful when cleaning up context fields: if this list is empty, it's safe to delete the context field.", "operationId": "getStrategiesByContextField", "parameters": [ { @@ -7230,6 +7263,7 @@ Note: passing \`null\` as a value for the description property will set it to an "description": "contextFieldStrategiesSchema", }, }, + "summary": "Get strategies using this context field", "tags": [ "Strategies", ],