From f799f72697602a2ee3631369aedf361aa8f1458d Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Tue, 4 Jul 2023 14:21:09 +0200 Subject: [PATCH] openapi: `strategies` tag (#4116) Update OpenAPI schemas and operation descriptions for the strategies tag. --- src/lib/openapi/index.ts | 6 +- src/lib/openapi/meta-schema-rules.test.ts | 2 - .../spec/context-field-strategies-schema.ts | 2 +- .../openapi/spec/create-strategy-schema.ts | 67 ++ src/lib/openapi/spec/index.ts | 3 +- src/lib/openapi/spec/name-schema.ts | 3 + src/lib/openapi/spec/strategies-schema.ts | 2 + src/lib/openapi/spec/strategy-schema.ts | 7 +- .../openapi/spec/update-strategy-schema.ts | 61 ++ .../openapi/spec/upsert-strategy-schema.ts | 41 - src/lib/routes/admin-api/context.ts | 30 +- src/lib/routes/admin-api/strategy.test.ts | 13 +- src/lib/routes/admin-api/strategy.ts | 79 +- .../__snapshots__/openapi.e2e.test.ts.snap | 759 ++++++++++++++++-- 14 files changed, 946 insertions(+), 129 deletions(-) create mode 100644 src/lib/openapi/spec/create-strategy-schema.ts create mode 100644 src/lib/openapi/spec/update-strategy-schema.ts delete mode 100644 src/lib/openapi/spec/upsert-strategy-schema.ts diff --git a/src/lib/openapi/index.ts b/src/lib/openapi/index.ts index 1e635fb6f7..a6cf0cc7b5 100644 --- a/src/lib/openapi/index.ts +++ b/src/lib/openapi/index.ts @@ -128,7 +128,8 @@ import { updateUserSchema, upsertContextFieldSchema, upsertSegmentSchema, - upsertStrategySchema, + createStrategySchema, + updateStrategySchema, userSchema, usersGroupsBaseSchema, usersSchema, @@ -323,7 +324,8 @@ export const schemas: UnleashSchemas = { updateTagsSchema, upsertContextFieldSchema, upsertSegmentSchema, - upsertStrategySchema, + createStrategySchema, + updateStrategySchema, userSchema, usersGroupsBaseSchema, usersSchema, diff --git a/src/lib/openapi/meta-schema-rules.test.ts b/src/lib/openapi/meta-schema-rules.test.ts index 9435b0ffdc..71cd13bbb2 100644 --- a/src/lib/openapi/meta-schema-rules.test.ts +++ b/src/lib/openapi/meta-schema-rules.test.ts @@ -119,7 +119,6 @@ const metaRules: Rule[] = [ 'maintenanceSchema', 'toggleMaintenanceSchema', 'meSchema', - 'nameSchema', 'passwordSchema', 'patchSchema', 'permissionSchema', @@ -203,7 +202,6 @@ const metaRules: Rule[] = [ 'maintenanceSchema', 'toggleMaintenanceSchema', 'meSchema', - 'nameSchema', 'parametersSchema', 'passwordSchema', 'patchesSchema', diff --git a/src/lib/openapi/spec/context-field-strategies-schema.ts b/src/lib/openapi/spec/context-field-strategies-schema.ts index 24f59513b1..75b3d77065 100644 --- a/src/lib/openapi/spec/context-field-strategies-schema.ts +++ b/src/lib/openapi/spec/context-field-strategies-schema.ts @@ -4,7 +4,7 @@ export const contextFieldStrategiesSchema = { $id: '#/components/schemas/segmentStrategiesSchema', type: 'object', description: - 'A wrapper object containing all for strategies using a specific context field', + 'A wrapper object containing all strategies that use a specific context field', required: ['strategies'], properties: { strategies: { diff --git a/src/lib/openapi/spec/create-strategy-schema.ts b/src/lib/openapi/spec/create-strategy-schema.ts new file mode 100644 index 0000000000..49635824cd --- /dev/null +++ b/src/lib/openapi/spec/create-strategy-schema.ts @@ -0,0 +1,67 @@ +import { FromSchema } from 'json-schema-to-ts'; + +export const createStrategySchema = { + $id: '#/components/schemas/createStrategySchema', + type: 'object', + description: + 'The data required to create a strategy type. Refer to the docs on [custom strategy types](https://docs.getunleash.io/reference/custom-activation-strategies) for more information.', + required: ['name', 'parameters'], + properties: { + name: { + type: 'string', + description: 'The name of the strategy type. Must be unique.', + example: 'my-custom-strategy', + }, + description: { + type: 'string', + description: 'A description of the strategy type.', + example: + 'Enable the feature for users who have not logged in before.', + }, + parameters: { + type: 'array', + description: + 'The parameter list lets you pass arguments to your custom activation strategy. These will be made available to your custom strategy implementation.', + items: { + type: 'object', + required: ['name', 'type'], + properties: { + name: { + type: 'string', + description: 'The name of the parameter', + example: 'Rollout percentage', + }, + type: { + type: 'string', + description: + 'The [type of the parameter](https://docs.getunleash.io/reference/custom-activation-strategies#parameter-types)', + enum: [ + 'string', + 'percentage', + 'list', + 'number', + 'boolean', + ], + example: 'percentage', + }, + description: { + type: 'string', + description: + 'A description of this strategy parameter. Use this to indicate to the users what the parameter does.', + example: + 'How many percent of users should see this feature?', + }, + required: { + type: 'boolean', + description: + 'Whether this parameter must be configured when using the strategy. Defaults to `false`', + example: false, + }, + }, + }, + }, + }, + components: {}, +} as const; + +export type CreateStrategySchema = FromSchema; diff --git a/src/lib/openapi/spec/index.ts b/src/lib/openapi/spec/index.ts index 338ce3237d..276f2ec608 100644 --- a/src/lib/openapi/spec/index.ts +++ b/src/lib/openapi/spec/index.ts @@ -84,7 +84,8 @@ export * from './client-features-schema'; export * from './feature-metrics-schema'; export * from './health-overview-schema'; export * from './update-tag-type-schema'; -export * from './upsert-strategy-schema'; +export * from './create-strategy-schema'; +export * from './update-strategy-schema'; export * from './create-api-token-schema'; export * from './export-query-parameters'; export * from './feature-strategy-schema'; diff --git a/src/lib/openapi/spec/name-schema.ts b/src/lib/openapi/spec/name-schema.ts index c3536e3a58..c9933d64b0 100644 --- a/src/lib/openapi/spec/name-schema.ts +++ b/src/lib/openapi/spec/name-schema.ts @@ -5,8 +5,11 @@ export const nameSchema = { type: 'object', additionalProperties: false, required: ['name'], + description: 'An object with a name', properties: { name: { + description: 'The name of the represented object.', + example: 'betaUser', type: 'string', }, }, diff --git a/src/lib/openapi/spec/strategies-schema.ts b/src/lib/openapi/spec/strategies-schema.ts index 9d0acc3267..bd829bf1e1 100644 --- a/src/lib/openapi/spec/strategies-schema.ts +++ b/src/lib/openapi/spec/strategies-schema.ts @@ -9,6 +9,8 @@ export const strategiesSchema = { properties: { version: { type: 'integer', + enum: [1], + example: 1, }, strategies: { type: 'array', diff --git a/src/lib/openapi/spec/strategy-schema.ts b/src/lib/openapi/spec/strategy-schema.ts index 0282bbfb31..bb856e0921 100644 --- a/src/lib/openapi/spec/strategy-schema.ts +++ b/src/lib/openapi/spec/strategy-schema.ts @@ -23,7 +23,7 @@ export const strategySchema = { }, name: { type: 'string', - description: 'The name or type of the strategy', + description: 'The name (type) of the strategy', example: 'flexibleRollout', }, displayName: { @@ -34,12 +34,13 @@ export const strategySchema = { }, description: { type: 'string', - description: 'A short description for the strategy', + description: 'A short description of the strategy', example: 'Gradual rollout to logged in users', }, editable: { type: 'boolean', - description: 'Determines whether the strategy allows for editing', + description: + 'Whether the strategy can be edited or not. Strategies bundled with Unleash cannot be edited.', example: true, }, deprecated: { diff --git a/src/lib/openapi/spec/update-strategy-schema.ts b/src/lib/openapi/spec/update-strategy-schema.ts new file mode 100644 index 0000000000..fd97816cc0 --- /dev/null +++ b/src/lib/openapi/spec/update-strategy-schema.ts @@ -0,0 +1,61 @@ +import { FromSchema } from 'json-schema-to-ts'; + +export const updateStrategySchema = { + $id: '#/components/schemas/updateStrategySchema', + type: 'object', + description: 'The data required to update a strategy type.', + required: ['parameters'], + properties: { + description: { + type: 'string', + description: 'A description of the strategy type.', + example: + 'Enable the feature for users who have not logged in before.', + }, + parameters: { + type: 'array', + description: + 'The parameter list lets you pass arguments to your custom activation strategy. These will be made available to your custom strategy implementation.', + items: { + type: 'object', + required: ['name', 'type'], + properties: { + name: { + type: 'string', + description: 'The name of the parameter', + example: 'Rollout percentage', + }, + type: { + type: 'string', + description: + 'The [type of the parameter](https://docs.getunleash.io/reference/custom-activation-strategies#parameter-types)', + enum: [ + 'string', + 'percentage', + 'list', + 'number', + 'boolean', + ], + example: 'percentage', + }, + description: { + type: 'string', + description: + 'A description of this strategy parameter. Use this to indicate to the users what the parameter does.', + example: + 'How many percent of users should see this feature?', + }, + required: { + type: 'boolean', + description: + 'Whether this parameter must be configured when using the strategy. Defaults to `false`', + example: false, + }, + }, + }, + }, + }, + components: {}, +} as const; + +export type UpdateStrategySchema = FromSchema; diff --git a/src/lib/openapi/spec/upsert-strategy-schema.ts b/src/lib/openapi/spec/upsert-strategy-schema.ts deleted file mode 100644 index 3d9fc0fb5a..0000000000 --- a/src/lib/openapi/spec/upsert-strategy-schema.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { FromSchema } from 'json-schema-to-ts'; - -export const upsertStrategySchema = { - $id: '#/components/schemas/upsertStrategySchema', - type: 'object', - required: ['name'], - properties: { - name: { - type: 'string', - }, - description: { - type: 'string', - }, - editable: { - type: 'boolean', - }, - parameters: { - type: 'array', - items: { - type: 'object', - properties: { - name: { - type: 'string', - }, - type: { - type: 'string', - }, - description: { - type: 'string', - }, - required: { - type: 'boolean', - }, - }, - }, - }, - }, - components: {}, -} as const; - -export type UpsertStrategySchema = FromSchema; diff --git a/src/lib/routes/admin-api/context.ts b/src/lib/routes/admin-api/context.ts index 572b4d52a2..dd6ac0cb94 100644 --- a/src/lib/routes/admin-api/context.ts +++ b/src/lib/routes/admin-api/context.ts @@ -31,8 +31,14 @@ import { import { serializeDates } from '../../types/serialize-dates'; import NotFoundError from '../../error/notfound-error'; import { NameSchema } from '../../openapi/spec/name-schema'; -import { emptyResponse } from '../../openapi/util/standard-responses'; -import { contextFieldStrategiesSchema } from '../../openapi/spec/context-field-strategies-schema'; +import { + emptyResponse, + getStandardResponses, +} from '../../openapi/util/standard-responses'; +import { + ContextFieldStrategiesSchema, + contextFieldStrategiesSchema, +} from '../../openapi/spec/context-field-strategies-schema'; interface ContextParam { contextField: string; @@ -103,13 +109,15 @@ 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', + summary: 'Get strategies that use a context field', + description: + "Retrieves a list of all strategies that use the specified context field. If the context field doesn't exist, returns an empty list of strategies", responses: { 200: createResponseSchema( 'contextFieldStrategiesSchema', ), + ...getStandardResponses(401), }, }), ], @@ -241,10 +249,14 @@ export class ContextController extends Controller { value, userName, ); - res.status(201) - .header('location', `context/${result.name}`) - .json(serializeDates(result)) - .end(); + + this.openApiService.respondWithValidation( + 201, + res, + contextFieldSchema.$id, + serializeDates(result), + { location: `context/${result.name}` }, + ); } async updateContextField( @@ -284,7 +296,7 @@ export class ContextController extends Controller { async getStrategiesByContextField( req: IAuthRequest<{ contextField: string }>, - res: Response, + res: Response, ): Promise { const { contextField } = req.params; const contextFields = diff --git a/src/lib/routes/admin-api/strategy.test.ts b/src/lib/routes/admin-api/strategy.test.ts index 62542d33bb..55a83eb94a 100644 --- a/src/lib/routes/admin-api/strategy.test.ts +++ b/src/lib/routes/admin-api/strategy.test.ts @@ -63,15 +63,14 @@ test('require a name when creating a new strategy', async () => { test('require parameters array when creating a new strategy', async () => { const { request, base } = await getSetup(); - return request + const { body } = await request .post(`${base}/api/admin/strategies`) .send({ name: 'TestStrat' }) - .expect(400) - .expect((res) => { - expect(res.body.details[0].description).toMatch( - '"parameters" is required', - ); - }); + .expect(400); + + const detailsDescription = body.details[0].description; + expect(detailsDescription).toEqual(expect.stringMatching('parameters')); + expect(detailsDescription).toEqual(expect.stringMatching('required')); }); test('create a new strategy with empty parameters', async () => { diff --git a/src/lib/routes/admin-api/strategy.ts b/src/lib/routes/admin-api/strategy.ts index 940080ad46..16c6489e40 100644 --- a/src/lib/routes/admin-api/strategy.ts +++ b/src/lib/routes/admin-api/strategy.ts @@ -13,7 +13,10 @@ import { import { Request, Response } from 'express'; import { IAuthRequest } from '../unleash-types'; import { OpenApiService } from '../../services/openapi-service'; -import { emptyResponse } from '../../openapi/util/standard-responses'; +import { + emptyResponse, + getStandardResponses, +} from '../../openapi/util/standard-responses'; import { createRequestSchema } from '../../openapi/util/create-request-schema'; import { createResponseSchema, @@ -27,7 +30,8 @@ import { strategiesSchema, StrategiesSchema, } from '../../openapi/spec/strategies-schema'; -import { UpsertStrategySchema } from '../../openapi/spec/upsert-strategy-schema'; +import { CreateStrategySchema } from '../../openapi/spec/create-strategy-schema'; +import { UpdateStrategySchema } from '../../openapi/spec/update-strategy-schema'; const version = 1; @@ -57,10 +61,14 @@ class StrategyController extends Controller { permission: NONE, middleware: [ openApiService.validPath({ + summary: 'Get all strategies', + description: + 'Retrieves all strategy types ([predefined](https://docs.getunleash.io/reference/activation-strategies "predefined strategies") and [custom strategies](https://docs.getunleash.io/reference/custom-activation-strategies)) that are defined on this Unleash instance.', tags: ['Strategies'], operationId: 'getAllStrategies', responses: { 200: createResponseSchema('strategiesSchema'), + ...getStandardResponses(401), }, }), ], @@ -73,9 +81,16 @@ class StrategyController extends Controller { permission: NONE, middleware: [ openApiService.validPath({ + summary: 'Get a strategy definition', + description: + 'Retrieves the definition of the strategy specified in the URL', + tags: ['Strategies'], operationId: 'getStrategy', - responses: { 200: createResponseSchema('strategySchema') }, + responses: { + 200: createResponseSchema('strategySchema'), + ...getStandardResponses(401, 404), + }, }), ], }); @@ -88,9 +103,14 @@ class StrategyController extends Controller { acceptAnyContentType: true, middleware: [ openApiService.validPath({ + summary: 'Delete a strategy', + description: 'Deletes the specified strategy definition', tags: ['Strategies'], operationId: 'removeStrategy', - responses: { 200: emptyResponse }, + responses: { + 200: emptyResponse, + ...getStandardResponses(401, 403, 404), + }, }), ], }); @@ -104,9 +124,13 @@ class StrategyController extends Controller { openApiService.validPath({ tags: ['Strategies'], operationId: 'createStrategy', - requestBody: createRequestSchema('upsertStrategySchema'), + summary: 'Create a strategy', + description: + 'Creates a strategy type based on the supplied data.', + requestBody: createRequestSchema('createStrategySchema'), responses: { 201: resourceCreatedResponseSchema('strategySchema'), + ...getStandardResponses(401, 403, 409, 415), }, }), ], @@ -120,9 +144,15 @@ class StrategyController extends Controller { middleware: [ openApiService.validPath({ tags: ['Strategies'], + summary: 'Update a strategy type', + description: + 'Updates the specified strategy type. Any properties not specified in the request body are left untouched.', operationId: 'updateStrategy', - requestBody: createRequestSchema('upsertStrategySchema'), - responses: { 200: emptyResponse }, + requestBody: createRequestSchema('updateStrategySchema'), + responses: { + 200: emptyResponse, + ...getStandardResponses(401, 403, 404, 415), + }, }), ], }); @@ -136,8 +166,13 @@ class StrategyController extends Controller { middleware: [ openApiService.validPath({ tags: ['Strategies'], + summary: 'Deprecate a strategy', + description: 'Marks the specified strategy as deprecated.', operationId: 'deprecateStrategy', - responses: { 200: emptyResponse }, + responses: { + 200: emptyResponse, + ...getStandardResponses(401, 403, 404), + }, }), ], }); @@ -152,7 +187,13 @@ class StrategyController extends Controller { openApiService.validPath({ tags: ['Strategies'], operationId: 'reactivateStrategy', - responses: { 200: emptyResponse }, + summary: 'Reactivate a strategy', + description: + "Marks the specified strategy as not deprecated. If the strategy wasn't already deprecated, nothing changes.", + responses: { + 200: emptyResponse, + ...getStandardResponses(401, 403, 404), + }, }), ], }); @@ -197,7 +238,7 @@ class StrategyController extends Controller { } async createStrategy( - req: IAuthRequest, + req: IAuthRequest, res: Response, ): Promise { const userName = extractUsername(req); @@ -206,19 +247,25 @@ class StrategyController extends Controller { req.body, userName, ); - res.header('location', `strategies/${strategy.name}`) - .status(201) - .json(strategy) - .end(); + this.openApiService.respondWithValidation( + 201, + res, + strategySchema.$id, + strategy, + { location: `strategies/${strategy.name}` }, + ); } async updateStrategy( - req: IAuthRequest, + req: IAuthRequest<{ strategyName: string }, UpdateStrategySchema>, res: Response, ): Promise { const userName = extractUsername(req); - await this.strategyService.updateStrategy(req.body, userName); + await this.strategyService.updateStrategy( + { ...req.body, name: req.params.strategyName }, + userName, + ); res.status(200).end(); } 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 2ba7a97c3a..9d4b5e3283 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 @@ -1746,7 +1746,7 @@ The provider you choose for your addon dictates what properties the \`parameters "type": "object", }, "contextFieldStrategiesSchema": { - "description": "A wrapper object containing all for strategies using a specific context field", + "description": "A wrapper object containing all strategies that use a specific context field", "properties": { "strategies": { "description": "List of strategies using the context field", @@ -2009,6 +2009,66 @@ The provider you choose for your addon dictates what properties the \`parameters ], "type": "object", }, + "createStrategySchema": { + "description": "The data required to create a strategy type. Refer to the docs on [custom strategy types](https://docs.getunleash.io/reference/custom-activation-strategies) for more information.", + "properties": { + "description": { + "description": "A description of the strategy type.", + "example": "Enable the feature for users who have not logged in before.", + "type": "string", + }, + "name": { + "description": "The name of the strategy type. Must be unique.", + "example": "my-custom-strategy", + "type": "string", + }, + "parameters": { + "description": "The parameter list lets you pass arguments to your custom activation strategy. These will be made available to your custom strategy implementation.", + "items": { + "properties": { + "description": { + "description": "A description of this strategy parameter. Use this to indicate to the users what the parameter does.", + "example": "How many percent of users should see this feature?", + "type": "string", + }, + "name": { + "description": "The name of the parameter", + "example": "Rollout percentage", + "type": "string", + }, + "required": { + "description": "Whether this parameter must be configured when using the strategy. Defaults to \`false\`", + "example": false, + "type": "boolean", + }, + "type": { + "description": "The [type of the parameter](https://docs.getunleash.io/reference/custom-activation-strategies#parameter-types)", + "enum": [ + "string", + "percentage", + "list", + "number", + "boolean", + ], + "example": "percentage", + "type": "string", + }, + }, + "required": [ + "name", + "type", + ], + "type": "object", + }, + "type": "array", + }, + }, + "required": [ + "name", + "parameters", + ], + "type": "object", + }, "createUserSchema": { "additionalProperties": false, "properties": { @@ -3578,8 +3638,11 @@ The provider you choose for your addon dictates what properties the \`parameters }, "nameSchema": { "additionalProperties": false, + "description": "An object with a name", "properties": { "name": { + "description": "The name of the represented object.", + "example": "betaUser", "type": "string", }, }, @@ -5155,6 +5218,10 @@ Stats are divided into current and previous **windows**. "type": "array", }, "version": { + "enum": [ + 1, + ], + "example": 1, "type": "integer", }, }, @@ -5174,7 +5241,7 @@ Stats are divided into current and previous **windows**. "type": "boolean", }, "description": { - "description": "A short description for the strategy", + "description": "A short description of the strategy", "example": "Gradual rollout to logged in users", "type": "string", }, @@ -5185,12 +5252,12 @@ Stats are divided into current and previous **windows**. "type": "string", }, "editable": { - "description": "Determines whether the strategy allows for editing", + "description": "Whether the strategy can be edited or not. Strategies bundled with Unleash cannot be edited.", "example": true, "type": "boolean", }, "name": { - "description": "The name or type of the strategy", + "description": "The name (type) of the strategy", "example": "flexibleRollout", "type": "string", }, @@ -5627,6 +5694,60 @@ Stats are divided into current and previous **windows**. }, "type": "object", }, + "updateStrategySchema": { + "description": "The data required to update a strategy type.", + "properties": { + "description": { + "description": "A description of the strategy type.", + "example": "Enable the feature for users who have not logged in before.", + "type": "string", + }, + "parameters": { + "description": "The parameter list lets you pass arguments to your custom activation strategy. These will be made available to your custom strategy implementation.", + "items": { + "properties": { + "description": { + "description": "A description of this strategy parameter. Use this to indicate to the users what the parameter does.", + "example": "How many percent of users should see this feature?", + "type": "string", + }, + "name": { + "description": "The name of the parameter", + "example": "Rollout percentage", + "type": "string", + }, + "required": { + "description": "Whether this parameter must be configured when using the strategy. Defaults to \`false\`", + "example": false, + "type": "boolean", + }, + "type": { + "description": "The [type of the parameter](https://docs.getunleash.io/reference/custom-activation-strategies#parameter-types)", + "enum": [ + "string", + "percentage", + "list", + "number", + "boolean", + ], + "example": "percentage", + "type": "string", + }, + }, + "required": [ + "name", + "type", + ], + "type": "object", + }, + "type": "array", + }, + }, + "required": [ + "parameters", + ], + "type": "object", + }, "updateTagTypeSchema": { "properties": { "description": { @@ -5764,43 +5885,6 @@ Stats are divided into current and previous **windows**. ], "type": "object", }, - "upsertStrategySchema": { - "properties": { - "description": { - "type": "string", - }, - "editable": { - "type": "boolean", - }, - "name": { - "type": "string", - }, - "parameters": { - "items": { - "properties": { - "description": { - "type": "string", - }, - "name": { - "type": "string", - }, - "required": { - "type": "boolean", - }, - "type": { - "type": "string", - }, - }, - "type": "object", - }, - "type": "array", - }, - }, - "required": [ - "name", - ], - "type": "object", - }, "userSchema": { "additionalProperties": false, "description": "An Unleash user", @@ -7592,7 +7676,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.", + "description": "Retrieves a list of all strategies that use the specified context field. If the context field doesn't exist, returns an empty list of strategies", "operationId": "getStrategiesByContextField", "parameters": [ { @@ -7615,8 +7699,35 @@ Note: passing \`null\` as a value for the description property will set it to an }, "description": "contextFieldStrategiesSchema", }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, }, - "summary": "Get strategies using this context field", + "summary": "Get strategies that use a context field", "tags": [ "Strategies", ], @@ -13146,6 +13257,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 }, "/api/admin/strategies": { "get": { + "description": "Retrieves all strategy types ([predefined](https://docs.getunleash.io/reference/activation-strategies "predefined strategies") and [custom strategies](https://docs.getunleash.io/reference/custom-activation-strategies)) that are defined on this Unleash instance.", "operationId": "getAllStrategies", "responses": { "200": { @@ -13158,22 +13270,51 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 }, "description": "strategiesSchema", }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, }, + "summary": "Get all strategies", "tags": [ "Strategies", ], }, "post": { + "description": "Creates a strategy type based on the supplied data.", "operationId": "createStrategy", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/upsertStrategySchema", + "$ref": "#/components/schemas/createStrategySchema", }, }, }, - "description": "upsertStrategySchema", + "description": "createStrategySchema", "required": true, }, "responses": { @@ -13196,7 +13337,116 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 }, }, }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, + "409": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "There is already a feature called "my-awesome-feature".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NameExistsError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The provided resource can not be created or updated because it would conflict with the current state of the resource or with an already existing resource, respectively.", + }, + "415": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "We do not accept the content-type you provided (application/xml). Try using one of the content-types we do accept instead (application/json) and make sure the body is in the corresponding format.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "ContentTypeerror", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The operation does not support request payloads of the provided type. Please ensure that you're using one of the listed payload types and that you have specified the right content type in the "content-type" header.", + }, }, + "summary": "Create a strategy", "tags": [ "Strategies", ], @@ -13204,6 +13454,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 }, "/api/admin/strategies/{name}": { "delete": { + "description": "Deletes the specified strategy definition", "operationId": "removeStrategy", "parameters": [ { @@ -13219,12 +13470,95 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 "200": { "description": "This response has no body.", }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, + "404": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "Could not find the addon with ID "12345".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NotFoundError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The requested resource was not found.", + }, }, + "summary": "Delete a strategy", "tags": [ "Strategies", ], }, "get": { + "description": "Retrieves the definition of the strategy specified in the URL", "operationId": "getStrategy", "parameters": [ { @@ -13247,7 +13581,62 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 }, "description": "strategySchema", }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, + "404": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "Could not find the addon with ID "12345".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NotFoundError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The requested resource was not found.", + }, }, + "summary": "Get a strategy definition", "tags": [ "Strategies", ], @@ -13255,6 +13644,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 }, "/api/admin/strategies/{strategyName}": { "put": { + "description": "Updates the specified strategy type. Any properties not specified in the request body are left untouched.", "operationId": "updateStrategy", "parameters": [ { @@ -13270,18 +13660,127 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/upsertStrategySchema", + "$ref": "#/components/schemas/updateStrategySchema", }, }, }, - "description": "upsertStrategySchema", + "description": "updateStrategySchema", "required": true, }, "responses": { "200": { "description": "This response has no body.", }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, + "404": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "Could not find the addon with ID "12345".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NotFoundError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The requested resource was not found.", + }, + "415": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "We do not accept the content-type you provided (application/xml). Try using one of the content-types we do accept instead (application/json) and make sure the body is in the corresponding format.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "ContentTypeerror", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The operation does not support request payloads of the provided type. Please ensure that you're using one of the listed payload types and that you have specified the right content type in the "content-type" header.", + }, }, + "summary": "Update a strategy type", "tags": [ "Strategies", ], @@ -13289,6 +13788,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 }, "/api/admin/strategies/{strategyName}/deprecate": { "post": { + "description": "Marks the specified strategy as deprecated.", "operationId": "deprecateStrategy", "parameters": [ { @@ -13304,7 +13804,89 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 "200": { "description": "This response has no body.", }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, + "404": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "Could not find the addon with ID "12345".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NotFoundError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The requested resource was not found.", + }, }, + "summary": "Deprecate a strategy", "tags": [ "Strategies", ], @@ -13312,6 +13894,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 }, "/api/admin/strategies/{strategyName}/reactivate": { "post": { + "description": "Marks the specified strategy as not deprecated. If the strategy wasn't already deprecated, nothing changes.", "operationId": "reactivateStrategy", "parameters": [ { @@ -13327,7 +13910,89 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 "200": { "description": "This response has no body.", }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, + "404": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "Could not find the addon with ID "12345".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NotFoundError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The requested resource was not found.", + }, }, + "summary": "Reactivate a strategy", "tags": [ "Strategies", ],