NestJS最佳实践--#9 OpenAPI与Swagger构建API文档
文章发布在专栏NestJS最佳实践中
通过OpenAPI和Swagger, 我们可以构建一个交互式的API文档。常有同学会混淆二者的概念,因此有必要分别介绍下OpenAPI和Swagger的区别。
- OpenAPI: 是定义一个标准的、与具体编程语言无关的RESTful API的规范。OpenAPI 规范使得人类和计算机都能在“不接触任何程序源代码和文档、不监控网络通信”的情况下理解一个服务的作用。如果您在定义您的 API 时做的很好,那么使用 API 的人就能非常轻松地理解您提供的 API 并与之交互了。
- Swagger: 是一系列围绕OpenAPI规范构建的工具集合。我们在本文中使用的是其中一种工具--Swagger UI。它允许我们将编写的RESTful API以文档的进行呈现,并可以在页面上访问和测试接口。
OpenAPI规范以前被称为Swagger规范,因此可能会对很多同学造成疑惑。
设置Swagger
安装依赖
# fastify
pnpm install --save @nestjs/swagger fastify-swagger @fastify/static
如果你使用express, 安装
swagger-ui-express
而不是fastify-swagger
初始化Swagger
在main.ts
文件中设置Swagger的初始化
// ...
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
async function bootstrap() {
// ...
const config = new DocumentBuilder()
.setTitle('NestJS Swagger')
.setDescription('API description')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
设置完成后,启动Nest应用, 运行pnpm start:dev并访问Swagger http://localhost:3000/api。
Swagger API 默认暴露在http://localhost:3000/api 你可以通过
SwaggerModule.setup('api',...)
设置该路径。同时你也可以访问json路径
- express: http://localhost:3000/api-json
- fastify: http://localhost:3000/api/json
到目前为止文档中并没有展示更多细节,没有请求体,没有响应体。接下来我们要通过OpenAPI的装饰器来设置接口的请求体和响应体。
OpenAPI 装饰器
所有可用的OpenAPI装饰器都有一个Api前缀,以将它们与核心装饰器区分开来。我们重点介绍其中三个常用的装饰器。
@ApiTags()
在控制器级别使用@ApiTags(…tags)
将同一个Controller下的所有api分为一组。
@ApiTags('post') // 👈
@Controller('post')
export class PostController {
// ...
}
可以看到下图中所有与文章相关的api都被分配到post下
@ApiProperty()
该方法常用于 *.dto.ts
和 *.entity.ts
文件中,将属性暴漏给Swagger.
给QueryPostDto
的search
属性添加@ApiProperty()
装饰器
@DtoValidation({ groups: ['query'] })
export class QueryPostDto extends PaginationDto {
@ApiProperty() // 👈
@MaxLength(100, {
always: true,
message: '搜索字符串长度不得超过$constraint1',
})
@IsOptional({ always: true })
// 搜索条件可以是 post的 title, body, summary 也可以是 Category的name
search?: string;
}
经过上面设置就可以在Swagger中看到请求体了
@ApiResponse()
给post.entity.ts
的title
属性加上@ApiProperty()
@Exclude()
@Entity('post')
export class Post {
// ...
@ApiProperty() // 👈
@Expose()
@Column({ comment: '文章标题' })
@Index({ fulltext: true })
title!: string;
// ...
}
此外,Swagger需要指定响应类型。使用自定义@ApiResponse()
注释REST端点,指定状态代码和响应类型,或者选择一个short-hand API response(例如@ApiOkResponse()
、@ApiCreatedResponse()
…)
@ApiOkResponse
:GET
和DELETE
@ApiCreatedResponse
:POST
和PATCH
@ApiForbiddenResponse
: 接口可能抛出 forbidden (403
) exception
@ApiTags('post')
@Controller('post')
export class PostController {
constructor(private readonly postService: PostService) {}
@Post('search')
@ApiResponse({ type: [PostEntity] }) // 👈 array notation
search(@Body() data: QueryPostDto) {
return this.postService.search(data);
}
// ...
}
经过上面设置后就可以在Swagger中看到响应体了
Swagger CLI Plugin
如果项目中包含很多业务模块UserController
、PostController
...,每个业务模块又会涉及很多的 dto
和entity
文件。如果每个文件都要使用装饰器处理一遍,未免有些过于复杂了。好在 我们可以使用 Swagger CLI Plugin 来自动完成上述步骤。
只需在nest-cli.json
中开启插件
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"plugins": [
"@nestjs/swagger" // 👈 enable plugin
]
}
}
我们就可以得到一个较为完善的api文档了
导入Insomnia
Insomnia是一款类似Postman的接口管理工具
输入swagger的json路径即可
最终一次性导入应用中的所有api, 并且api所需要的请求体都已经填充好了,只需要更改为真实数据即可。
转载自:https://juejin.cn/post/7217780935538130999