## 操作
在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>
```
- 介绍
- 概述
- 第一步
- 控制器
- 提供者
- 模块
- 中间件
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 自定义装饰器
- 基础知识
- 自定义提供者
- 异步提供者
- 动态模块
- 注入作用域
- 循环依赖
- 模块参考
- 懒加载模块
- 应用上下文
- 生命周期事件
- 跨平台
- 测试
- 技术
- 数据库
- Mongo
- 配置
- 验证
- 缓存
- 序列化
- 版本控制
- 定时任务
- 队列
- 日志
- Cookies
- 事件
- 压缩
- 文件上传
- 流式处理文件
- HTTP模块
- Session(会话)
- MVC
- 性能(Fastify)
- 服务器端事件发送
- 安全
- 认证(Authentication)
- 授权(Authorization)
- 加密和散列
- Helmet
- CORS(跨域请求)
- CSRF保护
- 限速
- GraphQL
- 快速开始
- 解析器(resolvers)
- 变更(Mutations)
- 订阅(Subscriptions)
- 标量(Scalars)
- 指令(directives)
- 接口(Interfaces)
- 联合类型
- 枚举(Enums)
- 字段中间件
- 映射类型
- 插件
- 复杂性
- 扩展
- CLI插件
- 生成SDL
- 其他功能
- 联合服务
- 迁移指南
- Websocket
- 网关
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 适配器
- 微服务
- 概述
- Redis
- MQTT
- NATS
- RabbitMQ
- Kafka
- gRPC
- 自定义传输器
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 独立应用
- Cli
- 概述
- 工作空间
- 库
- 用法
- 脚本
- Openapi
- 介绍
- 类型和参数
- 操作
- 安全
- 映射类型
- 装饰器
- CLI插件
- 其他特性
- 迁移指南
- 秘籍
- CRUD 生成器
- 热重载
- MikroORM
- TypeORM
- Mongoose
- 序列化
- 路由模块
- Swagger
- 健康检查
- CQRS
- 文档
- Prisma
- 静态服务
- Nest Commander
- 问答
- Serverless
- HTTP 适配器
- 全局路由前缀
- 混合应用
- HTTPS 和多服务器
- 请求生命周期
- 常见错误
- 实例
- 迁移指南
- 发现
- 谁在使用Nest?