Skip to content

Commit

Permalink
feat: same status code multiple response example support
Browse files Browse the repository at this point in the history
  • Loading branch information
slowquery committed Jul 17, 2021
1 parent 4740848 commit 6310278
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 3 deletions.
6 changes: 6 additions & 0 deletions lib/decorators/api-response.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ import {
} from '../interfaces/open-api-spec.interface';
import { getTypeIsArrayTuple } from './helpers';

export interface ApiResponseExmaples {
summary: string;
value: unknown;
}

export interface ApiResponseMetadata
extends Omit<ResponseObject, 'description'> {
status?: number | 'default';
type?: Type<unknown> | Function | [Function] | string;
isArray?: boolean;
description?: string;
examples?: { [key: string]: ApiResponseExmaples };
}

export interface ApiResponseSchemaHost
Expand Down
7 changes: 6 additions & 1 deletion lib/services/mimetype-content-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ export class MimetypeContentWrapper {
obj: Record<string, any>
): Record<'content', ContentObject> {
const content = mimetype.reduce(
(acc, item) => ({ ...acc, [item]: obj }),
(acc, item) => {
if (obj.examples === undefined) {
delete obj.examples;
}
return { ...acc, [item]: obj };
},
{}
);
return { content };
Expand Down
10 changes: 8 additions & 2 deletions lib/services/response-object-mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class ResponseObjectMapper {
name: string,
produces: string[]
) {
const examples = response.examples;
delete response.examples;
return {
...response,
...this.mimetypeContentWrapper.wrap(produces, {
Expand All @@ -19,18 +21,22 @@ export class ResponseObjectMapper {
items: {
$ref: getSchemaPath(name)
}
}
},
examples
})
};
}

toRefObject(response: Record<string, any>, name: string, produces: string[]) {
const examples = response.examples;
delete response.examples;
return {
...response,
...this.mimetypeContentWrapper.wrap(produces, {
schema: {
$ref: getSchemaPath(name)
}
},
examples
})
};
}
Expand Down
44 changes: 44 additions & 0 deletions test/explorer/swagger-explorer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ describe('SwaggerExplorer', () => {
enumArr: LettersEnum;
}

class ErrorEntitiesDto {
@ApiProperty()
isError: boolean;

@ApiProperty()
reason: string;
}

@Controller('')
class FooController {
@Post('foos')
Expand All @@ -87,6 +95,26 @@ describe('SwaggerExplorer', () => {
type: Foo,
description: 'Newly created Foo object'
})
@ApiBadRequestResponse({
type: Foo,
description: 'Invalid parameter error',
examples: {
ParameterInvalidName: {
summary: 'failure create foo object (invalid name)',
value: {
isError: true,
reason: 'Foo parameter name is invalid'
}
},
ParameterInvalidEmail: {
summary: 'failure create foo object (invalid email)',
value: {
isError: true,
reason: 'Foo parameter email is invalid'
}
}
}
})
create(
@Body() createFoo: CreateFoo,
@Query() listEntities: ListEntitiesDto
Expand All @@ -105,6 +133,22 @@ describe('SwaggerExplorer', () => {
}
}

it('sees two examples for error responses by same response code', () => {
const explorer = new SwaggerExplorer(schemaObjectFactory);
const routes = explorer.exploreController(
{
instance: new FooController(),
metatype: FooController
} as InstanceWrapper<FooController>,
new ApplicationConfig(),
'modulePath',
'globalPrefix'
);

expect((routes[0].responses['400'] as ResponseObject).content['application/json'].examples.ParameterInvalidName).toBeDefined();
expect((routes[0].responses['400'] as ResponseObject).content['application/json'].examples.ParameterInvalidEmail).toBeDefined();
});

it('sees two controller operations and their responses', () => {
const explorer = new SwaggerExplorer(schemaObjectFactory);
const routes = explorer.exploreController(
Expand Down

0 comments on commit 6310278

Please sign in to comment.