## 类型和参数
`SwaggerModule`在路径处理程序上搜索所有`@Body()`, `@Query()`, 以及`@Param()`装饰器来生成API文档。它也利用反射来创建响应模型。考虑以下代码:
```TypeScript
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
```
> 要显式定义主体,使用`@ApiBody()`装饰器 (从`@nestjs/swagger`引入).
基于`CreateCatDto`,将创建以下Swagger页面模型。
![](https://docs.nestjs.com/assets/swagger-dto.png)
如你所见,虽然类已经声明了一些属性,但这里的定义是空的。要使这些类属性在`SwaggerModule`中可见,我们要么用`@ApiProperty()`装饰器或使用`CLI`插件来自动生成:
```TypeScript
import { ApiProperty } from '@nestjs/swagger';
export class CreateCatDto {
@ApiProperty()
name: string;
@ApiProperty()
age: number;
@ApiProperty()
breed: string;
}
```
> 考虑使用Swagger插件(参见[CLI插件](#CLI插件))来自动生成以代替手动装饰每个属性。
打开浏览器确认生成的`CreateCatDto`模型:
![](https://docs.nestjs.com/assets/swagger-dto2.png)
`@ApiProperty()`装饰器也允许设置不同的原型对象属性:
```TypeScript
@ApiProperty({
description: 'The age of a cat',
minimum: 1,
default: 1,
})
age: number;
```
> 可以使用`@ApiPropertyOptional()`速记装饰器来替代显式输入`@ApiProperty({ required: false })`。
要显式指定属性类型,使用`type`字段:
```TypeScript
@ApiProperty({
type: Number,
})
age: number;
```
### 数组
当属性是数组时,我们必须手动指定数组类型:
```TypeScript
@ApiProperty({ type: [String] })
names: string[];
```
> 考虑使用Swagger 插件来自动发现数组
要么将类型作为数组的第一个元素(如上),要么将`isArray`属性设为`true`。
### 循环依赖
当你的类之间有循环依赖时,使用`SwaggerModul`提供的一个包含类型信息的懒函数。
```TypeScript
@ApiProperty({ type: () => Node })
node: Node;
```
> 考虑使用Swagger 插件来自动发现循环依赖
### 泛型和接口
由于`TypeScript`没有存储泛型或者接口的元数据,当你在DTO中使用他们的时候,`SwaggerModule`可能不会正确生成运行时的模型定义。基于此,下列代码不会被Swagger模块正确识别。
```TypeScript
createBulk(@Body() usersDto: CreateUserDto[])
```
要处理这些限制,需要显式配置类型:
```TypeScript
@ApiBody({ type: [CreateUserDto] })
createBulk(@Body() usersDto: CreateUserDto[])
```
### 枚举
要定义一个枚举,需要在`@ApiProperty`中用数组手动设置`enum`属性。
```TypeScript
@ApiProperty({ enum: ['Admin', 'Moderator', 'User']})
role: UserRole;
```
也可以如下定义一个真实的`TypeScript`泛型:
```TypeScript
export enum UserRole {
Admin = 'Admin',
Moderator = 'Moderator',
User = 'User',
}
```
可以在`@Query()`参数中配合`@ApiQuery()`装饰器直接使用`enum`:
```TypeScript
@ApiQuery({ name: 'role', enum: UserRole })
async filterByRole(@Query('role') role: UserRole = UserRole.User) {}
```
![](https://docs.nestjs.com/assets/enum_query.gif)
当`isArray`配置为`true`时, `enum`可以多选。
![](https://docs.nestjs.com/assets/enum_query_array.gif)
### 枚举原型
默认地,`enum`属性将为[Enum](https://swagger.io/docs/specification/data-models/enums/)在`parameter`上添加一个原始定义。
```TypeScript
- breed:
type: 'string'
enum:
- Persian
- Tabby
- Siamese
```
上述定义在大部分情况下工作良好。然而,如果你使用该定义作为输入在客户端生成代码时,可能会遇到属性包含重复枚举的情况,考虑以下代码:
```TypeScript
// generated client-side code
export class CatDetail {
breed: CatDetailEnum;
}
export class CatInformation {
breed: CatInformationEnum;
}
export enum CatDetailEnum {
Persian = 'Persian',
Tabby = 'Tabby',
Siamese = 'Siamese',
}
export enum CatInformationEnum {
Persian = 'Persian',
Tabby = 'Tabby',
Siamese = 'Siamese',
}
```
> 上述代码使用[NSwag](https://github.com/RicoSuter/NSwag)工具生成
现在可以看到有两个枚举完全一样,要处理这个问题,需要在装饰器的`enum`属性中传入`enumName`参数。
```TypeScript
export class CatDetail {
@ApiProperty({ enum: CatBreed, enumName: 'CatBreed' })
breed: CatBreed;
}
```
`enumName`属性使能`@nestjs/swagger`来将`CatBreed`转换为其原型,从而使`CatBreed`可重用:
```TypeScript
CatDetail:
type: 'object'
properties:
...
- breed:
schema:
$ref: '#/components/schemas/CatBreed'
CatBreed:
type: string
enum:
- Persian
- Tabby
- Siamese
```
> 任何包含`enum`属性的装饰器都有`enumName`
### 原始定义
在一些特殊场合(例如深度嵌套的数组和矩阵),你可能需要手动描述你的类型。
```TypeScript
@ApiProperty({
type: 'array',
items: {
type: 'array',
items: {
type: 'number',
},
},
})
coords: number[][];
```
类似地,要在控制器类中手动定义输入输出,使用`schema`属性:
```TypeScript
@ApiBody({
schema: {
type: 'array',
items: {
type: 'array',
items: {
type: 'number',
},
},
},
})
async create(@Body() coords: number[][]) {}
```
### 额外模型
要定义控制器中没有直接使用,但是需要被Swagger模块检查的额外的模型,使用`@ApiExtraModels()`装饰器:
```TypeScript
@ApiExtraModels(ExtraModel)
export class CreateCatDto {}
```
> 只需要对指定的model类使用一次`@ApiExtraModels()`
你也可以把一个选项对象和`extraModels`属性一起传递给`SwaggerModule#createDocument()` 方法:
```TypeScript
const document = SwaggerModule.createDocument(app, options, {
extraModels: [ExtraModel],
});
```
要获得一个模型的引用(`$ref`) ,使用`getSchemaPath(ExtraModel)`函数:
```TypeScript
'application/vnd.api+json': {
schema: { $ref: getSchemaPath(ExtraModel) },
},
```
### `oneOf`, `anyOf`, `allOf`
要组合原型,你可以使用`oneOf`,`anyOf` 或者`allOf`关键词([阅读更多](https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/)).
```TypeScript
@ApiProperty({
oneOf: [
{ $ref: getSchemaPath(Cat) },
{ $ref: getSchemaPath(Dog) },
],
})
pet: Cat | Dog;
```
如果你要定义一个多态数组(例如,数组成员跨越多个原型),你应该使用前节的原始定义来手动定义你的类型。
```TypeScript
type Pet = Cat | Dog;
@ApiProperty({
type: 'array',
items: {
oneOf: [
{ $ref: getSchemaPath(Cat) },
{ $ref: getSchemaPath(Dog) },
],
},
})
pets: Pet[];
```
> `getSchemaPath()`函数从`@nestjs/swagger`引入.
`Cat`和`Dog`都应该使用`@ApiExtraModels()`装饰器 (在类水平).
- 介绍
- 概述
- 第一步
- 控制器
- 提供者
- 模块
- 中间件
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 自定义装饰器
- 基础知识
- 自定义提供者
- 异步提供者
- 动态模块
- 注入作用域
- 循环依赖
- 模块参考
- 懒加载模块
- 应用上下文
- 生命周期事件
- 跨平台
- 测试
- 技术
- 数据库
- 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?