From 713c48c283233a0da668ab440407ef59463ac302 Mon Sep 17 00:00:00 2001 From: Tianning Li Date: Sun, 10 Mar 2024 18:00:52 -0700 Subject: [PATCH 1/2] Add response example --- lib/decorators/api-response.decorator.ts | 1 + lib/services/response-object-mapper.ts | 20 +++++++++++++------- test/explorer/swagger-explorer.spec.ts | 21 +++++++++++++++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/lib/decorators/api-response.decorator.ts b/lib/decorators/api-response.decorator.ts index 092c0b761..c30224a98 100644 --- a/lib/decorators/api-response.decorator.ts +++ b/lib/decorators/api-response.decorator.ts @@ -14,6 +14,7 @@ export interface ApiResponseMetadata type?: Type | Function | [Function] | string; isArray?: boolean; description?: string; + example?: any; } export interface ApiResponseSchemaHost diff --git a/lib/services/response-object-mapper.ts b/lib/services/response-object-mapper.ts index 48889da02..72d991f8d 100644 --- a/lib/services/response-object-mapper.ts +++ b/lib/services/response-object-mapper.ts @@ -1,5 +1,5 @@ import { omit } from 'lodash'; -import { ApiResponseSchemaHost } from '../decorators'; +import { ApiResponseMetadata, ApiResponseSchemaHost } from '../decorators'; import { getSchemaPath } from '../utils'; import { MimetypeContentWrapper } from './mimetype-content-wrapper'; @@ -19,7 +19,8 @@ export class ResponseObjectMapper { items: { $ref: getSchemaPath(name) } - } + }, + ...(response.example ? { example: response.example } : {}) }) }; } @@ -30,20 +31,25 @@ export class ResponseObjectMapper { ...this.mimetypeContentWrapper.wrap(produces, { schema: { $ref: getSchemaPath(name) - } + }, + ...(response.example ? { example: response.example } : {}) }) }; } - wrapSchemaWithContent(response: ApiResponseSchemaHost, produces: string[]) { - if (!response.schema) { + wrapSchemaWithContent( + response: ApiResponseSchemaHost & ApiResponseMetadata, + produces: string[] + ) { + if (!response.schema && !response.example) { return response; } const content = this.mimetypeContentWrapper.wrap(produces, { - schema: response.schema + ...(response.schema ? { schema: response.schema } : {}), + ...(response.example ? { example: response.example } : {}) }); return { - ...omit(response, 'schema'), + ...omit(response, ['schema', 'example']), ...content }; } diff --git a/test/explorer/swagger-explorer.spec.ts b/test/explorer/swagger-explorer.spec.ts index 2870f7923..fc1c46e01 100644 --- a/test/explorer/swagger-explorer.spec.ts +++ b/test/explorer/swagger-explorer.spec.ts @@ -97,7 +97,11 @@ describe('SwaggerExplorer', () => { @ApiOperation({ summary: 'Create foo' }) @ApiCreatedResponse({ type: Foo, - description: 'Newly created Foo object' + description: 'Newly created Foo object', + example: { + id: 'foo', + name: 'Foo' + } }) create( @Body() createFoo: CreateFoo, @@ -138,7 +142,11 @@ describe('SwaggerExplorer', () => { @Post('foos') @ApiCreatedResponse({ type: Foo, - description: 'Newly created Foo object' + description: 'Newly created Foo object', + example: { + id: 'foo', + name: 'Foo' + } }) create( @Body() createFoo: CreateFoo, @@ -158,7 +166,11 @@ describe('SwaggerExplorer', () => { static [METADATA_FACTORY_NAME]() { return { create: { - summary: 'Create foo' + summary: 'Create foo', + example: { + id: 'foo', + name: 'Foo' + } }, find: { summary: 'List all Foos', @@ -301,7 +313,8 @@ describe('SwaggerExplorer', () => { ).toEqual({ schema: { $ref: '#/components/schemas/Foo' - } + }, + example: { id: 'foo', name: 'Foo' } }); // GET From e5adbe9cb0ac747e8cce5208e0f603262a67b4ae Mon Sep 17 00:00:00 2001 From: Tianning Li Date: Sun, 10 Mar 2024 18:22:05 -0700 Subject: [PATCH 2/2] Optimize dict --- lib/services/mimetype-content-wrapper.ts | 11 ++++++++++- lib/services/response-object-mapper.ts | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/services/mimetype-content-wrapper.ts b/lib/services/mimetype-content-wrapper.ts index 545d0444c..0f5054068 100644 --- a/lib/services/mimetype-content-wrapper.ts +++ b/lib/services/mimetype-content-wrapper.ts @@ -1,12 +1,21 @@ import { ContentObject } from '../interfaces/open-api-spec.interface'; +function removeUndefinedKeys(obj: { [x: string]: any }) { + Object.entries(obj).forEach(([key, value]) => { + if (value === undefined) { + delete obj[key]; + } + }); + return obj; +} + export class MimetypeContentWrapper { wrap( mimetype: string[], obj: Record ): Record<'content', ContentObject> { const content = mimetype.reduce( - (acc, item) => ({ ...acc, [item]: obj }), + (acc, item) => ({ ...acc, [item]: removeUndefinedKeys(obj) }), {} ); return { content }; diff --git a/lib/services/response-object-mapper.ts b/lib/services/response-object-mapper.ts index 72d991f8d..82d0dcc83 100644 --- a/lib/services/response-object-mapper.ts +++ b/lib/services/response-object-mapper.ts @@ -20,7 +20,7 @@ export class ResponseObjectMapper { $ref: getSchemaPath(name) } }, - ...(response.example ? { example: response.example } : {}) + example: response.example }) }; } @@ -32,7 +32,7 @@ export class ResponseObjectMapper { schema: { $ref: getSchemaPath(name) }, - ...(response.example ? { example: response.example } : {}) + example: response.example }) }; } @@ -45,8 +45,8 @@ export class ResponseObjectMapper { return response; } const content = this.mimetypeContentWrapper.wrap(produces, { - ...(response.schema ? { schema: response.schema } : {}), - ...(response.example ? { example: response.example } : {}) + schema: response.schema, + example: response.example }); return { ...omit(response, ['schema', 'example']),