首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

OpenAPI(Swagger)

本章仅适用于TypeScript

该OpenAPI的规范是一个功能强大的高清格式来描述RESTful API中。Nest提供了一个专用模块来使用它。

安装

首先,您必须安装模块:

代码语言:javascript
复制
$ npm install --save @nestjs/swagger

引导

安装过程完成后,打开引导程序文件(主要是main.ts)并使用SwaggerModule类初始化Swagger :

代码语言:javascript
复制
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ApplicationModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(ApplicationModule);

  const options = new DocumentBuilder()
    .setTitle('Cats example')
    .setDescription('The cats API description')
    .setVersion('1.0')
    .addTag('cats')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api', app, document);

  await app.listen(3001);
}
bootstrap();

DocumentBuilder是一个帮助程序类,有助于构建一个基本文档SwaggerModule。它包含几个允许设置标题,描述,版本等属性的方法。

为了创建一个完整的文档(使用已定义的HTTP路由),我们使用该类的createDocument()方法SwaggerModule。此方法分别使用两个参数,即应用程序实例和基本Swagger选项。

最后一步是调用setup()。它接受顺序(1)路径来安装Swagger,(2)应用程序实例,以及(3)描述Nest应用程序的文档。

现在,您可以运行以下命令来启动HTTP服务器:

代码语言:javascript
复制
$ npm run start

应用程序运行时,打开浏览器并导航到http://localhost:3000/api。你应该看到类似的页面:

SwaggerModule自动反映您的所有端点。在后台,它正在利用swagger-ui-express并创建一个实时文档。

正文,查询,路径参数

在定义控制器的检查,SwaggerModule寻找所有的使用@Body()@Query()以及@Param()在路由处理器装饰。多亏了他们,可以创建有效的文档。

此外,该模块通过利用反射创建模型定义。看一下下面的代码:

代码语言:javascript
复制
@Post()
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}

注意要隐式设置主体定义,可以使用@ApiImplicitBody()装饰器(@nestjs/swagger包)。

基于此CreateCatDto,将创建模块定义:

如您所见,虽然该类具有很少的声明属性,但该定义为空。为了使类属性可访问SwaggerModule,我们必须使用@ApiModelProperty()装饰器标记所有类:

代码语言:javascript
复制
import { ApiModelProperty } from '@nestjs/swagger';

export class CreateCatDto {
  @ApiModelProperty()
  readonly name: string;

  @ApiModelProperty()
  readonly age: number;

  @ApiModelProperty()
  readonly breed: string;
}

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

@ApiModelProperty()装饰接受选项对象:

代码语言:javascript
复制
export declare const ApiModelProperty: (metadata?: {
  description?: string;
  required?: boolean;
  type?: any;
  isArray?: boolean;
  collectionFormat?: string;
  default?: any;
  enum?: SwaggerEnumType;
  format?: string;
  multipleOf?: number;
  maximum?: number;
  exclusiveMaximum?: number;
  minimum?: number;
  exclusiveMinimum?: number;
  maxLength?: number;
  minLength?: number;
  pattern?: string;
  maxItems?: number;
  minItems?: number;
  uniqueItems?: boolean;
  maxProperties?: number;
  minProperties?: number;
  readOnly?: boolean;
  xml?: any;
  example?: any;
}) => PropertyDecorator;

提示有一个@ApiModelPropertyOptional()快捷方式装饰器,有助于避免连续输入 @ApiModelProperty({ required: false })

多亏了我们可以简单地设置默认值,确定属性是必需的还是显式设置类型。

多种规格

Swagger模块还提供了一种支持多种规范的方法。换句话说,您可以SwaggerUI在不同的端点上为不同的文档提供不同的文档。

为了SwaggerModule支持多规范,您的应用程序必须使用模块化方法编写。该createDocument()方法接受第三个参数:extraOptions这是一个属性include需要一组模块的对象。

您可以设置多个规范支持,如下所示:

代码语言:javascript
复制
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ApplicationModule } from './app.module';

// imports CatsModule and DogsModule;

async function bootstrap() {
  const app = await NestFactory.create(ApplicationModule);

  /**
   * createDocument(application, configurationOptions, extraOptions);
   *
   * createDocument method takes in an optional 3rd argument "extraOptions"
   * which is an object with "include" property where you can pass an Array
   * of Modules that you want to include in that Swagger Specification
   * E.g: CatsModule and DogsModule will have two separate Swagger Specifications which
   * will be exposed on two different SwaggerUI with two different endpoints.
   */

  const options = new DocumentBuilder()
    .setTitle('Cats example')
    .setDescription('The cats API description')
    .setVersion('1.0')
    .addTag('cats')
    .build();
  const catDocument = SwaggerModule.createDocument(app, options, { include: [CatsModule] });
  SwaggerModule.setup('api/cats', app, catDocument);

  const secondOptions = new DocumentBuilder()
    .setTitle('Dogs example')
    .setDescription('The dogs API description')
    .setVersion('1.0')
    .addTag('dogs')
    .build();
  const dogDocument = SwaggerModule.createDocument(app, secondOptions, { include: [DogsModule] });
  SwaggerModule.setup('api/dogs', app, dogDocument);

  await app.listen(3001);
}
bootstrap();

现在,您可以使用以下命令启动服务器:

代码语言:javascript
复制
$ npm run start

导航到http://localhost:3000/api/cats您的Cats查看SwaggerUI:

虽然http://localhost:3000/api/docs会为你的狗暴露一个SwaggerUI:

请注意,您必须构建一个SwaggerOptionsDocumentBuilder运行createDocument()对新建options然后立即“伺候”它setup(),然后才能开始在第二个工作SwaggerOptions为第二扬鞭规范。此特定顺序是为了防止Swagger配置被不同选项覆盖。

使用枚举

为了能够SwaggerModule识别Enum,我们必须使用值数组手动设置enum属性@ApiModelProperty

代码语言:javascript
复制
@ApiModelProperty({ enum: ['Admin', 'Moderator', 'User']})
role: UserRole;

UserRole 枚举可以定义为以下代码段:

代码语言:javascript
复制
export enum UserRole {
  Admin = 'Admin',
  Moderator = 'Moderator',
  User = 'User'
}

注意上述用法只能作为模型定义的一部分应用于属性。

枚举可以单独使用@Query()参数装饰器与@ApiImplicitQuery()装饰器结合使用。

代码语言:javascript
复制
@ApiImplicitQuery({ name: 'role', enum: ['Admin', 'Moderator', 'User'] })
async filterByRole(@Query('role') role: UserRole = UserRole.User) {
  // role returns: UserRole.Admin, UserRole.Moderator OR UserRole.User
}

提示enumisArray也可以组合中可以使用@ApiImplicitQuery()

随着isArray设置为,则enum现在可以选择作为一个多选

使用数组

当属性实际上是一个数组时,我们必须手动指示一个类型:

代码语言:javascript
复制
@ApiModelProperty({ type: [String] })
readonly names: string[];

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

标签

一开始,我们创建了一个cats标签(通过利用DocumentBuilder)。为了将控制器附加到指定的标签,我们需要使用@ApiUseTags(...tags)装饰器。

代码语言:javascript
复制
@ApiUseTags('cats')
@Controller('cats')
export class CatsController {}

回应

要定义自定义HTTP响应,我们使用@ApiResponse()装饰器。

代码语言:javascript
复制
@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);
}

异常过滤器部分中定义的常见HTTP异常相同,Nest还提供了一组从核心装饰器继承的可用API响应@ApiResponse

  • @ApiOkResponse()
  • @ApiCreatedResponse()
  • @ApiBadRequestResponse()
  • @ApiUnauthorizedResponse()
  • @ApiNotFoundResponse()
  • @ApiForbiddenResponse()
  • @ApiMethodNotAllowedResponse()
  • @ApiNotAcceptableResponse()
  • @ApiRequestTimeoutResponse()
  • @ApiConflictResponse()
  • @ApiGoneResponse()
  • @ApiPayloadTooLargeResponse()
  • @ApiUnsupportedMediaTypeResponse()
  • @ApiUnprocessableEntityResponse()
  • @ApiInternalServerErrorResponse()
  • @ApiNotImplementedResponse()
  • @ApiBadGatewayResponse()
  • @ApiServiceUnavailableResponse()
  • @ApiGatewayTimeoutResponse()

除了现有的HTTP例外,鸟巢提供速记装饰为:HttpStatus.OKHttpStatus.CREATEDHttpStatus.METHOD_NOT_ALLOWED

代码语言:javascript
复制
@Post()
@ApiCreatedResponse({ description: 'The record has been successfully created.'})
@ApiForbiddenResponse({ description: 'Forbidden.'})
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}

认证

您可以使用类的addBearerAuth()方法启用承载授权DocumentBuilder。然后限制所选路线或整个控制器,使用@ApiBearerAuth()装饰器。

代码语言:javascript
复制
@ApiUseTags('cats')
@ApiBearerAuth()
@Controller('cats')
export class CatsController {}

这就是OpenAPI文档现在的样子:

上传文件

您可以使用@ApiImplicitFile装饰器为特定方法启用文件上载@ApiConsumes()。以下是使用文件上传技术的完整示例:

代码语言:javascript
复制
@UseInterceptors(FileInterceptor('file'))
@ApiConsumes('multipart/form-data')
@ApiImplicitFile({ name: 'file', required: true, description: 'List of cats' })
uploadFile(@UploadedFile() file) {}

装饰

所有可用的OpenAPI装饰器都有一个Api前缀,可以清楚地区分核心装饰器。下面是具有已定义使用级别的导出装饰器的完整列表(可能应用的位置)。

@ApiOperation()

方法

@ApiResponse()

方法/控制器

@ApiProduces()

方法/控制器

@ApiConsumes()

方法/控制器

@ApiBearerAuth()

方法/控制器

@ApiOAuth2Auth()

方法/控制器

@ApiImplicitBody()

方法

@ApiImplicitParam()

方法

@ApiImplicitQuery()

方法

@ApiImplicitHeader()

方法

@ApiImplicitFile()

方法

@ApiExcludeEndpoint()

方法

@ApiUseTags()

方法/控制器

@ApiModelProperty()

模型

@ApiModelPropertyOptional()

模型

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com