ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 操作 在OpenAPI规范中,API暴露的以{资源}为结束的终端,例如`/users`或者`/reports/summary`,都是可以执行HTTP方法的,例如`GET`,`POST`或者`DELETE`。 ### 标签 要为控制器附加一个标签,使用`@ApiTags(...tags)装饰器。 ```TypeScript @ApiTags('cats') @Controller('cats') export class CatsController {} ``` ### 标头 要作为请求的一部分定义自定义标头,使用`@ApiHeader()`装饰器。 ```TypeScript @ApiHeader({ name: 'X-MyHeader', description: 'Custom header', }) @Controller('cats') export class CatsController {} ``` ### 响应 要定义一个自定义响应, 使用`@ApiResponse()装饰器. ```TypeScript @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() - @ApiBadRequestResponse() - @ApiUnauthorizedResponse() - @ApiNotFoundResponse() - @ApiForbiddenResponse() - @ApiMethodNotAllowedResponse() - @ApiNotAcceptableResponse() - @ApiRequestTimeoutResponse() - @ApiConflictResponse() - @ApiTooManyRequestsResponse() - @ApiGoneResponse() - @ApiPayloadTooLargeResponse() - @ApiUnsupportedMediaTypeResponse() - @ApiUnprocessableEntityResponse() - @ApiInternalServerErrorResponse() - @ApiNotImplementedResponse() - @ApiBadGatewayResponse() - @ApiServiceUnavailableResponse() - @ApiGatewayTimeoutResponse() - @ApiDefaultResponse() ```TypeScript @Post() @ApiCreatedResponse({ description: 'The record has been successfully created.'}) @ApiForbiddenResponse({ description: 'Forbidden.'}) async create(@Body() createCatDto: CreateCatDto) { this.catsService.create(createCatDto); } ``` 要从请求返回一个指定的模型,需要创建一个类并用`@ApiProperty()`装饰器注释它。 ```TypeScript export class Cat { @ApiProperty() id: number; @ApiProperty() name: string; @ApiProperty() age: number; @ApiProperty() breed: string; } ``` `Cat`模型可以与响应装饰器的`type`属性组合使用。 ```TypeScript @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`模型。 ![](https://docs.nestjs.com/assets/swagger-response-type.png) ### 文件上传 使用`@ApiBody`装饰器和`@ApiConsumes()`来使能文件上传,这里有一个完整的使用[文件上传](https://docs.nestjs.com/techniques/file-upload)技术的例子。 ```TypeScript @UseInterceptors(FileInterceptor('file')) @ApiConsumes('multipart/form-data') @ApiBody({ description: 'List of cats', type: FileUploadDto, }) uploadFile(@UploadedFile() file) {} ``` `FileUploadDto`像这样定义: ```TypeScript class FileUploadDto { @ApiProperty({ type: 'string', format: 'binary' }) file: any; } ``` 要处理多个文件上传,如下定义`FilesUploadDto`: ```TypeScript class FilesUploadDto { @ApiProperty({ type: 'array', items: { type: 'string', format: 'binary' } }) files: any[]; } ``` ### 扩展 要为请求增加一个扩展使用`@ApiExtension()`装饰器. 该扩展名称必须以 `x-`前缀。 ```TypeScript @ApiExtension('x-foo', { hello: 'world' }) ``` ### 高级主题:通用`ApiResponse` 基于[原始定义](https://docs.nestjs.com/openapi/types-and-parameters#raw-definitions),的能力,我们可以为Swagger定义通用原型: ```TypeScript export class PaginatedDto<TData> { @ApiProperty() total: number; @ApiProperty() limit: number; @ApiProperty() offset: number; results: TData[]; } ``` 我们跳过了定义`results`,因为后面要提供一个原始定义。现在,我们定义另一个DTO,例如`CatDto`如下: ```TypeScript export class CatDto { @ApiProperty() name: string; @ApiProperty() age: number; @ApiProperty() breed: string; } ``` 我们可以定义一个`PaginatedDto<CatDto>`响应如下: ```TypeScript @ApiOkResponse({ schema: { allOf: [ { $ref: getSchemaPath(PaginatedDto) }, { properties: { results: { type: 'array', items: { $ref: getSchemaPath(CatDto) }, }, }, }, ], }, }) async findAll(): Promise<PaginatedDto<CatDto>> {} ``` 在这个例子中,我们指定响应拥有所有的`PaginatedDto`并且`results`属性类型为`CatDto`数组。 - `getSchemaPath()` 函数从一个给定模型的OpenAPI指定文件返回OpenAPI原型路径 - `allOf`是一个OAS3的概念,包括各种各样相关用例的继承。 最后,因为`PaginatedDto`没有被任何控制器直接引用,`SwaggerModule`还不能生成一个相应的模型定义。我们需要一个[额外的模型](https://docs.nestjs.com/openapi/types-and-parameters#extra-models),可以在控制器水平使用`@ApiExtraModels()`装饰器。 ```TypeScript @Controller('cats') @ApiExtraModels(PaginatedDto) export class CatsController {} ``` 如果你现在运行Swagger,为任何终端生成的`swagger.json`文件看上去应该像定义的这样: ```JSON "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/PaginatedDto" }, { "properties": { "results": { "$ref": "#/components/schemas/CatDto" } } } ] } } } } } ``` 为了让其可重用,我们为`PaginatedDto`像这样创建一个装饰器: ```TypeScript export const ApiPaginatedResponse = <TModel extends Type<any>>( model: TModel, ) => { return applyDecorators( ApiOkResponse({ schema: { allOf: [ { $ref: getSchemaPath(PaginatedDto) }, { properties: { results: { type: 'array', items: { $ref: getSchemaPath(model) }, }, }, }, ], }, }), ); }; ``` > `Type<any>`接口和`applyDecorators`函数从`@nestjs/common`引入. 我们现在可以为终端使用自定义的`@ApiPaginatedResponse()`装饰器 : ```TypeScript @ApiPaginatedResponse(CatDto) async findAll(): Promise<PaginatedDto<CatDto>> {} ``` 作为客户端生成工具,这一方法为客户端提供了一个含糊的`PaginatedResponse<TModel>`。下面示例展示了生成的客户端访问`GET /`终端的结果。 ```TypeScript // Angular findAll(): Observable<{ total: number, limit: number, offset: number, results: CatDto[] }> ``` 可以看出,这里的返回类型是含糊不清的。要处理这个问题,可以为`ApiPaginatedResponse`的`原型`添加`title`属性。 ```TypeScript export const ApiPaginatedResponse = <TModel extends Type<any>>(model: TModel) => { return applyDecorators( ApiOkResponse({ schema: { title: `PaginatedResponseOf${model.name}` allOf: [ // ... ], }, }), ); }; ``` 现在结果变成了。 ```TypeScript // Angular findAll(): Observable<PaginatedResponseOfCatDto> ```