类型参数 Types and parameters

导读

SwaggerModule 在路由处理程序中搜索所有 @Body()@Query()@Param() 装饰器以生成 API 文档。它还利用反射创建相应的模型定义。请考虑以下代码:

ts
@Post()
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}
Hint

要显式设置主体定义,请使用 @ApiBody() 装饰器(从 @nestjs/swagger 包导入)。

基于 CreateCatDto,将创建以下模型定义 Swagger UI:

img

如您所见,尽管该类具有一些声明的属性,但该定义为空。为了使类属性对 SwaggerModule 可见,我们必须使用 @ApiProperty() 装饰器对其进行注释,或者使用 CLI 插件(在 插件 部分中阅读更多内容),它将自动执行此操作:

ts
import { ApiProperty } from '@nestjs/swagger'

export class CreateCatDto {
  @ApiProperty()
  name: string

  @ApiProperty()
  age: number

  @ApiProperty()
  breed: string
}
Hint

无需手动注释每个属性,请考虑使用 Swagger 插件(请参阅 插件 部分),它将自动为您提供此功能。

让我们打开浏览器并验证生成的 CreateCatDto 模型:

img

此外,@ApiProperty() 装饰器允许设置各种 Schema Object 属性:

ts
@ApiProperty({
  description: 'The age of a cat',
  minimum: 1,
  default: 1,
})
age: number;
Hint

您可以使用 @ApiPropertyOptional() 简写装饰器,而不必明确键入 {{"@ApiProperty({ required: false })"}}

为了明确设置属性的类型,请使用 type 键:

ts
@ApiProperty({
  type: Number,
})
age: number;

Arrays

当属性是数组时,我们必须手动指示数组类型,如下所示:

ts
@ApiProperty({ type: [String] })
names: string[];
Hint

考虑使用 Swagger 插件(请参阅 插件 部分),它将自动检测数组。

将类型作为数组的第一个元素(如上所示)或将isArray属性设置为true

循环依赖

当类之间存在循环依赖时,使用惰性函数为SwaggerModule提供类型信息:

ts
@ApiProperty({ type: () => Node })
node: Node;
提示

考虑使用 Swagger 插件(参见 插件 部分),它将自动检测循环依赖关系。

泛型和接口

由于 TypeScript 不存储有关泛型或接口的元数据,因此当您在 DTO 中使用它们时,SwaggerModule 可能无法在运行时正确生成模型定义。例如,Swagger 模块无法正确检查以下代码:

ts
createBulk(@Body() usersDto: CreateUserDto[])

为了克服这一限制,您可以明确设置类型:

ts
@ApiBody({ type: [CreateUserDto] })
createBulk(@Body() usersDto: CreateUserDto[])

Enums

要识别枚举,我们必须使用值数组手动设置@ApiProperty上的枚举属性。

ts
@ApiProperty({ enum: ['Admin', 'Moderator', 'User']})
role: UserRole;

或者,定义一个实际的 TypeScript 枚举,如下所示:

ts
export enum UserRole {
  Admin = 'Admin',
  Moderator = 'Moderator',
  User = 'User',
}

然后,您可以将枚举直接与@Query()参数装饰器结合使用,并与@ApiQuery()装饰器结合使用。

ts
@ApiQuery({ name: 'role', enum: UserRole })
async filterByRole(@Query('role') role: UserRole = UserRole.User) {}

img

isArray设置为true后,可以将枚举选择为多选

img

Enums schema

默认情况下,枚举属性将在参数上添加 Enum 的原始定义。

yaml
- breed:
    type: string
    enum:
      - Persian
      - Tabby
      - Siamese

上述规范在大多数情况下都适用。但是,如果您使用的工具将规范作为输入并生成客户端代码,则可能会遇到生成的代码包含重复的枚举的问题。请考虑以下代码片段:

ts
// 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 的工具生成的。

您可以看到现在有两个完全相同的 enums。 为了解决这个问题,您可以在装饰器中传递 enumNameenum 属性。

ts
export class CatDetail {
  @ApiProperty({ enum: CatBreed, enumName: 'CatBreed' })
  breed: CatBreed
}

enumName 属性使 @nestjs/swagger 能够将 CatBreed 转换为其自己的 schema,从而使 CatBreed 枚举可重复使用。规范如下所示:

yaml
CatDetail:
  type: 'object'
  properties:
    ...
    - breed:
        schema:
          $ref: '#/components/schemas/CatBreed'
CatBreed:
  type: string
  enum:
    - Persian
    - Tabby
    - Siamese
Hint

任何以 enum 作为属性的 装饰器 也将采用 enumName

Raw definitions

在某些特定场景中(例如,深度嵌套数组、矩阵),您可能需要手动描述您的类型。

ts
@ApiProperty({
  type: 'array',
  items: {
    type: 'array',
    items: {
      type: 'number',
    },
  },
})
coords: number[][];

同样,为了在控制器类中手动定义输入/输出内容,请使用 schema 属性:

ts
@ApiBody({
  schema: {
    type: 'array',
    items: {
      type: 'array',
      items: {
        type: 'number',
      },
    },
  },
})
async create(@Body() coords: number[][]) {}

Extra models

要定义控制器中未直接引用但应由 Swagger 模块检查的其他模型,请使用 @ApiExtraModels() 装饰器:

ts
@ApiExtraModels(ExtraModel)
export class CreateCatDto {}
Hint

您只需对特定模型类使用一次 @ApiExtraModels()

或者,您可以将指定了 extraModels 属性的选项对象传递给 SwaggerModule#createDocument() 方法,如下所示:

ts
const document = SwaggerModule.createDocument(app, options, {
  extraModels: [ExtraModel],
})

要获取模型的引用($ref),请使用 getSchemaPath(ExtraModel) 函数:

ts
'application/vnd.api+json': {
   schema: { $ref: getSchemaPath(ExtraModel) },
},

oneOf, anyOf, allOf

要组合模式,您可以使用 oneOfanyOfallOf 关键字(阅读更多)。

ts
@ApiProperty({
  oneOf: [
    { $ref: getSchemaPath(Cat) },
    { $ref: getSchemaPath(Dog) },
  ],
})
pet: Cat | Dog;

如果要定义多态数组(即,其成员跨越多个模式的数组),则应使用原始定义(参见上文)手动定义类型。

ts
type Pet = Cat | Dog;

@ApiProperty({
  type: 'array',
  items: {
    oneOf: [
      { $ref: getSchemaPath(Cat) },
      { $ref: getSchemaPath(Dog) },
    ],
  },
})
pets: Pet[];
Hint

getSchemaPath() 函数从 @nestjs/swagger 导入。

必须使用 @ApiExtraModels() 装饰器(在类级别)将 CatDog 定义为额外模型。