操作
在 OpenAPI 术语中,路径是你的 API 暴露的端点(资源),例如 /users 或 /reports/summary,而操作是用于操作这些路径的 HTTP 方法,例如 GET、POST 或 DELETE。
标签
要将控制器关联到特定标签,请使用 @ApiTags(...tags) 装饰器。
@ApiTags('cats')
@Controller('cats')
export class CatsController {}请求头
要定义请求中预期的自定义请求头,请使用 @ApiHeader()。
@ApiHeader({
name: 'X-MyHeader',
description: 'Custom header',
})
@Controller('cats')
export class CatsController {}响应
要定义自定义 HTTP 响应,请使用 @ApiResponse() 装饰器。
@Post()
@ApiResponse({ status: 201, description: 'The record has been successfully created.'})
@ApiResponse({ status: 403, description: 'Forbidden.'})
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}Nest 提供了一组从 @ApiResponse 装饰器继承的简写 API 响应装饰器:
@ApiOkResponse()@ApiCreatedResponse()@ApiAcceptedResponse()@ApiNoContentResponse()@ApiMovedPermanentlyResponse()@ApiFoundResponse()@ApiBadRequestResponse()@ApiUnauthorizedResponse()@ApiNotFoundResponse()@ApiForbiddenResponse()@ApiMethodNotAllowedResponse()@ApiNotAcceptableResponse()@ApiRequestTimeoutResponse()@ApiConflictResponse()@ApiPreconditionFailedResponse()@ApiTooManyRequestsResponse()@ApiGoneResponse()@ApiPayloadTooLargeResponse()@ApiUnsupportedMediaTypeResponse()@ApiUnprocessableEntityResponse()@ApiInternalServerErrorResponse()@ApiNotImplementedResponse()@ApiBadGatewayResponse()@ApiServiceUnavailableResponse()@ApiGatewayTimeoutResponse()@ApiDefaultResponse()
@Post()
@ApiCreatedResponse({ description: 'The record has been successfully created.'})
@ApiForbiddenResponse({ description: 'Forbidden.'})
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}要为请求指定返回模型,我们需要创建一个类,并使用 @ApiProperty() 装饰器标注所有属性。
export class Cat {
@ApiProperty()
id: number;
@ApiProperty()
name: string;
@ApiProperty()
age: number;
@ApiProperty()
breed: string;
}然后可以将 Cat 模型与响应装饰器的 type 属性结合使用。
@ApiTags('cats')
@Controller('cats')
export class CatsController {
@Post()
@ApiCreatedResponse({
description: 'The record has been successfully created.',
type: Cat,
})
async create(@Body() createCatDto: CreateCatDto): Promise<Cat> {
return this.catsService.create(createCatDto);
}
}打开浏览器并验证生成的 Cat 模型:

除了为每个端点或控制器单独定义响应之外,你还可以使用 DocumentBuilder 类为所有端点定义全局响应。当你希望为应用中的所有端点定义全局响应时(例如 401 Unauthorized 或 500 Internal Server Error 等错误),这种方式非常有用。
const config = new DocumentBuilder()
.addGlobalResponse({
status: 500,
description: 'Internal server error',
})
// other configurations
.build();文件上传
你可以将 @ApiBody 装饰器与 @ApiConsumes() 一起使用,为特定方法启用文件上传功能。以下是使用文件上传技术的完整示例:
@UseInterceptors(FileInterceptor('file'))
@ApiConsumes('multipart/form-data')
@ApiBody({
description: 'List of cats',
type: FileUploadDto,
})
uploadFile(@UploadedFile() file: Express.Multer.File) {}其中 FileUploadDto 的定义如下:
class FileUploadDto {
@ApiProperty({ type: 'string', format: 'binary' })
file: any;
}要处理多文件上传,可以按如下方式定义 FilesUploadDto:
class FilesUploadDto {
@ApiProperty({ type: 'array', items: { type: 'string', format: 'binary' } })
files: any[];
}扩展
要为请求添加扩展,请使用 @ApiExtension() 装饰器。扩展名称必须以 x- 为前缀。
@ApiExtension('x-foo', { hello: 'world' })进阶:泛型 ApiResponse
借助提供原始定义的能力,我们可以为 Swagger UI 定义泛型 schema。假设我们有以下 DTO:
export class PaginatedDto<TData> {
@ApiProperty()
total: number;
@ApiProperty()
limit: number;
@ApiProperty()
offset: number;
results: TData[];
}我们跳过了对 results 的装饰,因为稍后会为其提供原始定义。现在,让我们定义另一个 DTO,将其命名为 CatDto:
export class CatDto {
@ApiProperty()
name: string;
@ApiProperty()
age: number;
@ApiProperty()
breed: string;
}有了这些准备,我们可以按如下方式定义 PaginatedDto<CatDto> 的响应:
@ApiOkResponse({
schema: {
allOf: [
{ $ref: getSchemaPath(PaginatedDto) },
{
properties: {
results: {
type: 'array',
items: { $ref: getSchemaPath(CatDto) },
},
},
},
],
},
})
async findAll(): Promise<PaginatedDto<CatDto>> {}在这个示例中,我们指定响应将包含 PaginatedDto 的所有属性(allOf),并且 results 属性的类型为 Array<CatDto>。
getSchemaPath()函数返回给定模型在 OpenAPI Spec 文件中的 OpenAPI Schema 路径。allOf是 OAS 3 提供的一个概念,用于处理各种与继承相关的用例。
最后,由于 PaginatedDto 没有被任何控制器直接引用,SwaggerModule 目前还无法生成对应的模型定义。在这种情况下,我们需要将其添加为额外模型。例如,我们可以在控制器级别使用 @ApiExtraModels() 装饰器:
@Controller('cats')
@ApiExtraModels(PaginatedDto)
export class CatsController {}运行 Swagger 后,该端点生成的 swagger.json 应包含如下响应定义:
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"allOf": [
{
"$ref": "#/components/schemas/PaginatedDto"
},
{
"properties": {
"results": {
"$ref": "#/components/schemas/CatDto"
}
}
}
]
}
}
}
}
}为了使其可复用,我们可以为 PaginatedDto 创建一个自定义装饰器:
export const ApiPaginatedResponse = <TModel extends Type<any>>(
model: TModel,
) => {
return applyDecorators(
ApiExtraModels(PaginatedDto, model),
ApiOkResponse({
schema: {
allOf: [
{ $ref: getSchemaPath(PaginatedDto) },
{
properties: {
results: {
type: 'array',
items: { $ref: getSchemaPath(model) },
},
},
},
],
},
}),
);
};提示
Type<any> 接口和 applyDecorators 函数从 @nestjs/common 包导入。
为确保 SwaggerModule 能为我们的模型生成定义,我们必须像之前在控制器中对 PaginatedDto 所做的那样,将其添加为额外模型。
完成上述准备后,我们就可以在端点上使用自定义的 @ApiPaginatedResponse() 装饰器了:
@ApiPaginatedResponse(CatDto)
async findAll(): Promise<PaginatedDto<CatDto>> {}对于客户端代码生成工具,这种方式在生成 PaginatedResponse<TModel> 时会存在类型歧义。以下是上述 GET / 端点的客户端生成结果示例:
// Angular
findAll(): Observable<{ total: number, limit: number, offset: number, results: CatDto[] }>可以看到,这里的返回类型是模糊的。为了解决这个问题,你可以在 ApiPaginatedResponse 的 schema 中添加 title 属性:
export const ApiPaginatedResponse = <TModel extends Type<any>>(
model: TModel,
) => {
return applyDecorators(
ApiOkResponse({
schema: {
title: `PaginatedResponseOf${model.name}`,
allOf: [
// ...
],
},
}),
);
};这样,客户端生成工具的结果将变为:
// Angular
findAll(): Observable<PaginatedResponseOfCatDto>