赞
踩
2020-01-11 • admin • NestJS入门swagger,快速搭建restfulApi文档已关闭评论条评论 • 550 次浏览
*由于最近新版@nestjs/swagger4.*的更新,使用的注解也发生了一些改动,具体可以查看
swagger:一个功能强大的高清格式来描述RESTful API
。Nest提供了专用的模块来使用它
yarn add @nestjs/swagger swagger-ui-express --save
如果使用fastify,则必须安装fastify-swagger而不是swagger-ui-express:
yarn add @nestjs/swagger fastify-swagger --save
- // 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、参数、请求响应等配置
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";
- name: string;
- description?: string;
- required?: boolean;
- 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提供装饰器即可,无需开发过后再回来编写文档
- // user.controller.ts 加上如下方法
- @Post('/add')
- public addUser(@Body() user: User) {
- return 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] })
- @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
- 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只有用户模块的文档
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。