NestJS入门swagger,快速搭建restfulApi文档

adminNestJS入门swagger,快速搭建restfulApi文档已关闭评论条评论 172 次浏览

swagger

*由于最近新版@nestjs/swagger4.*的更新,使用的注解也发生了一些改动,具体可以查看

@nestjs/swagger官方地址

swagger:一个功能强大的高清格式来描述RESTful API。Nest提供了专用的模块来使用它

1. 安装swagger

yarn add @nestjs/swagger swagger-ui-express --save
  • 1
如果使用fastify,则必须安装fastify-swagger而不是swagger-ui-express:
yarn add @nestjs/swagger fastify-swagger --save
  • 1

2.配置文档格式信息

// main.ts 中配置
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
// api文档插件
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// DocumentBuilder是一个辅助类,有助于结构的基本文件SwaggerModule。它包含几种方法,可用于设置诸如标题,描述,版本等属性。
  const options = new DocumentBuilder()
    .setTitle('nest入门接口标题')
    .setDescription('使用nest书写的常用性接口') // 文档介绍
    .setVersion('1.0.0') // 文档版本
    .addTag('用户,安全') // 每个tag标签都可以对应着几个@ApiUseTags('用户,安全') 然后被ApiUseTags注释,字符串一致的都会变成同一个标签下的
    // .setBasePath('http://localhost:5000')
    .build();
  // 为了创建完整的文档(具有定义的HTTP路由),我们使用类的createDocument()方法SwaggerModule。此方法带有两个参数,分别是应用程序实例和基本Swagger选项。
  const document = SwaggerModule.createDocument(app, options);
   // 最后一步是setup()。它依次接受(1)装入Swagger的路径,(2)应用程序实例, (3)描述Nest应用程序的文档。
  SwaggerModule.setup('/api', app, document);
   await app.listen(5000);
1.先通过DocumentBuilder实例来设置文档的配置选项,例如版本、标题、文档介绍、多个标签等
2.然后通过@nestjs/swagger模块提供的SwaggerModule的createDocument方法创建文档,传递整个app(应用程序实例)为第一个参数,第二个参数就是1配置号的文档选项
3.第三步是通过SwaggerModule的setup方法出口创建文档的url,它依次接受(1)装入Swagger的路径,(2)应用程序实例, (3)描述Nest应用程序的文档。
这时候会变成默认的配置文档选项
这时候启动默认初始化的项目,访问http://localhost:3000/api/

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

然后返回正确的状态和数据,文档都无需自己手写,减少不少的文档编辑量
定义控制器时,SwaggerModule寻找所有的使用@Body(),@Query()以及@Param()在路由处理器装饰。因此,可以创建有效的文档。

2.1 我们创建user文件夹,存放user相关的module,controller,service,代码如下:

// user.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class UserService {
    public getUser(id: string): string {
        return `用户的id:${id}`;
    }
}
// user.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('/user')
export class UserController {
    constructor(private userService: UserService) { }
    @Get('/get/:id')
    public getUser(@Param('id') id: string): string {
        return this.userService.getUser(id);
    }
}
// user.module.ts
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';

@Module({
    providers: [UserService],
    controllers: [UserController],
})
export class UserModule { }
// user.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { UserController } from './user.controller';
import { UserService } from './user.service';

describe('UserController', () => {
  let userController: UserController;

  beforeEach(async () => {
    const app: TestingModule = await Test.createTestingModule({
      controllers: [UserController],
      providers: [UserService],
    }).compile();

    userController = app.get<UserController>(UserController);
  });

  describe('user', () => {
    it('should return "用户的id: xxx"', () => {
      expect(userController.getUser('111')).toBe('用户的id:111');
    });
  });
});
这时候我们看一下swagger的文档,发现多了/user/get/{id}这个get请求的路由。

在这里插入图片描述

当然,这样往往是不足够的,swagger还提供了修饰dto、参数、请求响应等配置

3.swagger的配置装饰器

swagger的配置装饰器都是以@api开头

3.1 ApiTags装饰器,让对应的模块分类到对应的标签当中
在user.controller.ts中添加该装饰器在控制器类上
import { ApiTags } from '@nestjs/swagger';
import { Controller, Get, Query } from '@nestjs/common';
@ApiTags('用户,安全')
@Controller('/user')
export class UserController {
	//...
}
然后对应的这个控制器就分配到该组

在这里插入图片描述

3.2 ApiQuery、ApiBody、ApiParam、ApiHeader、ApiHeaders

除了ApiImplicitHeaders之外,其它的接收一个对象,对象类型如下:

name: string; // 该数据的名称,比如:id可以写用户id或者id
description?: string; // 简介
required?: boolean; // 是否是必须的
type?: any; // 类型
isArray?: boolean; // 是否是数组
enum?: SwaggerEnumType; // 枚举类型
collectionFormat?: "csv" | "ssv" | "tsv" | "pipes" | "multi";
而ApiHeaders需要的对象只有三个参数
 name: string;
 description?: string;
 required?: boolean;
修改user.controller.ts文件成如下代码:
import { Controller, Get, Param, Query } from '@nestjs/common';
import { ApiTags, ApiParam, ApiQuery, ApiHeader } from '@nestjs/swagger';
import { UserService } from './user.service';

@ApiTags('用户,安全')
@Controller('/user')
export class UserController {
    constructor(private userService: UserService) { }
    @Get('/get/:id')
    @ApiParam({
        name: 'id',
        description: '这是用户id',
    })
    @ApiQuery({
        name: 'role',
        description: '这是需要传递的参数',
    })
    @ApiHeader({
        name: 'authoriation',
        required: true,
        description: '本次请求请带上token',
    })
    public getUser(@Param('id') id: string, @Query('role') role: string): string {
        return this.userService.getUser(id);
    }
}
保存,刷新页面

在这里插入图片描述
会发现变成,对应的字段有对应的描述信息
在这里插入图片描述
我们只需要在编写接口的同时添加swagger提供装饰器即可,无需开发过后再回来编写文档

3.3 还有就是dto的参数配置ApiProperty

// user.controller.ts 加上如下方法
    @Post('/add')
    public addUser(@Body() user: User) {
        return user;
    }
创建一个User对象
// User.ts
import { ApiProperty } from '@nestjs/swagger';

export class User {
    @ApiProperty({
        description: '用户名',
    })
    username: string;
    @ApiProperty({
        description: '密码',
    })
    password: string;
}
这时候的文档

在这里插入图片描述

ApiProperty可以接受的对象配置参数有许多,具体可以参考官方

https://docs.nestjs.com/recipes/swagger

当参数是数组的情况下,我们可以这样配置@ApiProperty({ type: [String] })

3.4 还有就是ApiResponse,用来装饰方法
	@ApiResponse({ status: 401, description: '权限不足'})
	@Post('/add')
	public addUser(@Body() user: User) {
	   return user;
	}

在这里插入图片描述

nestjs还内置了大量的相关http状态码的描述,具体可以参照官方https://docs.nestjs.com/recipes/swagger

3.5 ApiImplicitFile 可以用于文件上传的文档测试

例如在addUser方法加上该装饰器

    @ApiResponse({ status: 401, description: '权限不足'})
    @ApiImplicitFile({
        name: '头像',
        description: '上传头像',
        required: false,
    })
    @Post('/add')
    public addUser(@Body() user: User) {
        return user;
    }

这时候,我们可以看见文档就是这样的:
在这里插入图片描述

具体使用还需要结合实际,以上全部装饰器都来自@nestjs/swagger
如果需要继续深入,可以观看官方文档的案例

4. 多个swagger文档,有时候我们需要分为前台接口和后台接口的情况下,我们可以编写多个文档

修改,把上面的文档拆分成两个文档
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { UserModule } from './user/user.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const options = new DocumentBuilder()
    .setTitle('用户信息文档')
    .setDescription('用于用户信息的增删改查')
    .setVersion('1.0')
    .addTag('用户,安全')
    .build();

  const userDocument = SwaggerModule.createDocument(app, options, {
    include: [UserModule], // 包含的模块
  });
  SwaggerModule.setup('api/user', app, userDocument);

  const secondOptions = new DocumentBuilder()
    .setTitle('整体文档')
    .setDescription('包含了测试文档和前台应用文档')
    .setVersion('1.0')
    .addTag('用户,安全')
    .build();

  const appDocument = SwaggerModule.createDocument(app, secondOptions, {
    include: [AppModule, UserModule],
  });
  SwaggerModule.setup('api', app, appDocument);

  await app.listen(3000);
}
bootstrap();
这时候,我们的文档就分成了 http://localhost:3000/api 这个整体文档和 用户模块的文档 http://localhost:3000/api/user
我们发现http://localhost:3000/api和前面的一致,而http://localhost:3000/api/user只有用户模块的文档