diff --git a/src/lib/openapi/meta-schema-rules.test.ts b/src/lib/openapi/meta-schema-rules.test.ts index 9ff8ddb860..175e3ddbd4 100644 --- a/src/lib/openapi/meta-schema-rules.test.ts +++ b/src/lib/openapi/meta-schema-rules.test.ts @@ -117,17 +117,12 @@ const metaRules: Rule[] = [ 'splashSchema', 'stateSchema', 'strategiesSchema', - 'tagTypeSchema', - 'tagTypesSchema', - 'tagWithVersionSchema', 'uiConfigSchema', 'updateFeatureSchema', - 'updateTagTypeSchema', 'upsertContextFieldSchema', 'upsertStrategySchema', 'usersGroupsBaseSchema', 'validateEdgeTokensSchema', - 'validateTagTypeSchema', 'variantFlagSchema', 'versionSchema', 'projectOverviewSchema', @@ -173,18 +168,13 @@ const metaRules: Rule[] = [ 'sortOrderSchema', 'splashSchema', 'strategiesSchema', - 'tagTypeSchema', - 'tagTypesSchema', - 'tagWithVersionSchema', 'uiConfigSchema', 'updateFeatureSchema', - 'updateTagTypeSchema', 'upsertContextFieldSchema', 'upsertStrategySchema', 'usersGroupsBaseSchema', 'usersSearchSchema', 'validateEdgeTokensSchema', - 'validateTagTypeSchema', 'variantFlagSchema', 'variantsSchema', 'versionSchema', diff --git a/src/lib/openapi/spec/tag-type-schema.ts b/src/lib/openapi/spec/tag-type-schema.ts index f746ab052f..12574dfb86 100644 --- a/src/lib/openapi/spec/tag-type-schema.ts +++ b/src/lib/openapi/spec/tag-type-schema.ts @@ -4,17 +4,24 @@ export const tagTypeSchema = { $id: '#/components/schemas/tagTypeSchema', type: 'object', additionalProperties: false, + description: 'A tag type.', required: ['name'], properties: { name: { type: 'string', + description: 'The name of the tag type.', + example: 'color', }, description: { type: 'string', + description: 'The description of the tag type.', + example: 'A tag type for describing the color of a tag.', }, icon: { type: 'string', nullable: true, + description: 'The icon of the tag type.', + example: 'not-really-used', }, }, components: {}, diff --git a/src/lib/openapi/spec/tag-types-schema.ts b/src/lib/openapi/spec/tag-types-schema.ts index ac95abe78f..311084c92e 100644 --- a/src/lib/openapi/spec/tag-types-schema.ts +++ b/src/lib/openapi/spec/tag-types-schema.ts @@ -6,12 +6,18 @@ export const tagTypesSchema = { type: 'object', additionalProperties: false, required: ['version', 'tagTypes'], + description: + 'A list of tag types with a version number representing the schema used to model the tag types.', properties: { version: { type: 'integer', + description: + 'The version of the schema used to model the tag types.', + example: 1, }, tagTypes: { type: 'array', + description: 'The list of tag types.', items: { $ref: '#/components/schemas/tagTypeSchema', }, diff --git a/src/lib/openapi/spec/tag-with-version-schema.ts b/src/lib/openapi/spec/tag-with-version-schema.ts index e09b4435ab..16dd7e6181 100644 --- a/src/lib/openapi/spec/tag-with-version-schema.ts +++ b/src/lib/openapi/spec/tag-with-version-schema.ts @@ -6,9 +6,13 @@ export const tagWithVersionSchema = { type: 'object', additionalProperties: false, required: ['version', 'tag'], + description: + 'A tag with a version number representing the schema used to model the tag.', properties: { version: { type: 'integer', + description: 'The version of the schema used to model the tag.', + example: 1, }, tag: { $ref: '#/components/schemas/tagSchema', diff --git a/src/lib/openapi/spec/update-tag-type-schema.ts b/src/lib/openapi/spec/update-tag-type-schema.ts index c814a2d7c8..7ae2a2f75c 100644 --- a/src/lib/openapi/spec/update-tag-type-schema.ts +++ b/src/lib/openapi/spec/update-tag-type-schema.ts @@ -3,12 +3,17 @@ import { FromSchema } from 'json-schema-to-ts'; export const updateTagTypeSchema = { $id: '#/components/schemas/updateTagTypeSchema', type: 'object', + description: 'The request body for updating a tag type.', properties: { description: { type: 'string', + description: 'The description of the tag type.', + example: 'A tag type for describing the color of a tag.', }, icon: { type: 'string', + description: 'The icon of the tag type.', + example: 'not-really-used', }, }, components: {}, diff --git a/src/lib/openapi/spec/validate-tag-type-schema.ts b/src/lib/openapi/spec/validate-tag-type-schema.ts index 1d669eab82..aebdc5ed9a 100644 --- a/src/lib/openapi/spec/validate-tag-type-schema.ts +++ b/src/lib/openapi/spec/validate-tag-type-schema.ts @@ -5,9 +5,12 @@ export const validateTagTypeSchema = { $id: '#/components/schemas/validateTagTypeSchema', type: 'object', required: ['valid', 'tagType'], + description: 'The result of validating a tag type.', properties: { valid: { type: 'boolean', + description: 'Whether or not the tag type is valid.', + example: true, }, tagType: { $ref: '#/components/schemas/tagTypeSchema', diff --git a/src/lib/routes/admin-api/tag-type.ts b/src/lib/routes/admin-api/tag-type.ts index 5dc0bfc3c9..5ebbbf5659 100644 --- a/src/lib/routes/admin-api/tag-type.ts +++ b/src/lib/routes/admin-api/tag-type.ts @@ -25,7 +25,10 @@ import { } from '../../openapi/spec/tag-type-schema'; import { UpdateTagTypeSchema } from '../../openapi/spec/update-tag-type-schema'; import { OpenApiService } from '../../services/openapi-service'; -import { emptyResponse } from '../../openapi/util/standard-responses'; +import { + emptyResponse, + getStandardResponses, +} from '../../openapi/util/standard-responses'; const version = 1; @@ -56,7 +59,12 @@ class TagTypeController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'getTagTypes', - responses: { 200: createResponseSchema('tagTypesSchema') }, + summary: 'Get all tag types', + description: 'Get a list of all available tag types.', + responses: { + 200: createResponseSchema('tagTypesSchema'), + ...getStandardResponses(401, 403), + }, }), ], }); @@ -69,8 +77,11 @@ class TagTypeController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'createTagType', + summary: 'Create a tag type', + description: 'Create a new tag type.', responses: { 201: resourceCreatedResponseSchema('tagTypeSchema'), + ...getStandardResponses(400, 401, 403, 409, 415), }, requestBody: createRequestSchema('tagTypeSchema'), }), @@ -85,8 +96,12 @@ class TagTypeController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'validateTagType', + summary: 'Validate a tag type', + description: + 'Validates whether if the body of the request is a valid tag and whether the a tag type with that name already exists or not. If a tag type with the same name exists, this operation will return a 409 status code.', responses: { 200: createResponseSchema('validateTagTypeSchema'), + ...getStandardResponses(400, 401, 403, 409, 415), }, requestBody: createRequestSchema('tagTypeSchema'), }), @@ -101,8 +116,11 @@ class TagTypeController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'getTagType', + summary: 'Get a tag type', + description: 'Get a tag type by name.', responses: { 200: createResponseSchema('tagTypeSchema'), + ...getStandardResponses(401, 403), }, }), ], @@ -116,8 +134,12 @@ class TagTypeController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'updateTagType', + summary: 'Update a tag type', + description: + 'Update the configuration for the specified tag type.', responses: { 200: emptyResponse, + ...getStandardResponses(400, 401, 403, 415), }, requestBody: createRequestSchema('updateTagTypeSchema'), }), @@ -133,8 +155,12 @@ class TagTypeController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'deleteTagType', + summary: 'Delete a tag type', + description: + 'Deletes a tag type. If any features have tags of this type, those tags will be deleted.', responses: { 200: emptyResponse, + ...getStandardResponses(401, 403), }, }), ], diff --git a/src/lib/routes/admin-api/tag.ts b/src/lib/routes/admin-api/tag.ts index 3bc171e2c9..65afe240ec 100644 --- a/src/lib/routes/admin-api/tag.ts +++ b/src/lib/routes/admin-api/tag.ts @@ -21,7 +21,10 @@ import { tagWithVersionSchema, TagWithVersionSchema, } from '../../openapi/spec/tag-with-version-schema'; -import { emptyResponse } from '../../openapi/util/standard-responses'; +import { + emptyResponse, + getStandardResponses, +} from '../../openapi/util/standard-responses'; import FeatureTagService from 'lib/services/feature-tag-service'; import { IFlagResolver } from '../../types'; @@ -65,7 +68,12 @@ class TagController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'getTags', - responses: { 200: createResponseSchema('tagsSchema') }, + summary: 'List all tags.', + description: 'List all tags available in Unleash.', + responses: { + 200: createResponseSchema('tagsSchema'), + ...getStandardResponses(401, 403), + }, }), ], }); @@ -78,10 +86,13 @@ class TagController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'createTag', + summary: 'Create a new tag.', + description: 'Create a new tag with the specified data.', responses: { 201: resourceCreatedResponseSchema( 'tagWithVersionSchema', ), + ...getStandardResponses(400, 401, 403, 409, 415), }, requestBody: createRequestSchema('tagSchema'), }), @@ -97,8 +108,12 @@ class TagController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'getTagsByType', + summary: 'List all tags of a given type.', + description: + 'List all tags of a given type. If the tag type does not exist it returns an empty list.', responses: { 200: createResponseSchema('tagsSchema'), + ...getStandardResponses(401, 403), }, }), ], @@ -112,8 +127,12 @@ class TagController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'getTag', + summary: 'Get a tag by type and value.', + description: + 'Get a tag by type and value. Can be used to check whether a given tag already exists in Unleash or not.', responses: { 200: createResponseSchema('tagWithVersionSchema'), + ...getStandardResponses(401, 403, 404), }, }), ], @@ -128,6 +147,9 @@ class TagController extends Controller { openApiService.validPath({ tags: ['Tags'], operationId: 'deleteTag', + summary: 'Delete a tag.', + description: + 'Delete a tag by type and value. When a tag is deleted all references to the tag are removed.', responses: { 200: emptyResponse, }, diff --git a/src/lib/services/addon-service.ts b/src/lib/services/addon-service.ts index 3d5e8b9d5b..8251bda3b4 100644 --- a/src/lib/services/addon-service.ts +++ b/src/lib/services/addon-service.ts @@ -170,7 +170,7 @@ export default class AddonService { const tagTypes = provider.definition.tagTypes || []; const createTags = tagTypes.map(async (tagType) => { try { - await this.tagTypeService.validateUnique(tagType); + await this.tagTypeService.validateUnique(tagType.name); await this.tagTypeService.createTagType( tagType, providerName, diff --git a/src/lib/services/tag-type-service.ts b/src/lib/services/tag-type-service.ts index 9ece507ba1..a919b9dfd6 100644 --- a/src/lib/services/tag-type-service.ts +++ b/src/lib/services/tag-type-service.ts @@ -48,7 +48,7 @@ export default class TagTypeService { const data = (await tagTypeSchema.validateAsync( newTagType, )) as ITagType; - await this.validateUnique(data); + await this.validateUnique(data.name); await this.tagTypeStore.createTagType(data); await this.eventStore.store({ type: TAG_TYPE_CREATED, @@ -58,7 +58,7 @@ export default class TagTypeService { return data; } - async validateUnique({ name }: Pick): Promise { + async validateUnique(name: string): Promise { const exists = await this.tagTypeStore.exists(name); if (exists) { throw new NameExistsError( @@ -68,9 +68,11 @@ export default class TagTypeService { return Promise.resolve(true); } - async validate(tagType: ITagType): Promise { + async validate(tagType: Partial | undefined): Promise { await tagTypeSchema.validateAsync(tagType); - await this.validateUnique(tagType); + if (tagType && tagType.name) { + await this.validateUnique(tagType.name); + } } async deleteTagType(name: string, userName: string): Promise {