likes
comments
collection
share

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

作者站长头像
站长
· 阅读数 13

文章发布在专栏NestJS最佳实践

代码地址:github.com/slashspaces…

通过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。

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

Swagger API 默认暴露在http://localhost:3000/api 你可以通过 SwaggerModule.setup('api',...) 设置该路径。

同时你也可以访问json路径

到目前为止文档中并没有展示更多细节,没有请求体,没有响应体。接下来我们要通过OpenAPI的装饰器来设置接口的请求体和响应体。

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

OpenAPI 装饰器

所有可用的OpenAPI装饰器都有一个Api前缀,以将它们与核心装饰器区分开来。我们重点介绍其中三个常用的装饰器。

@ApiTags()

在控制器级别使用@ApiTags(…tags)将同一个Controller下的所有api分为一组。

@ApiTags('post') // 👈 
@Controller('post')
export class PostController {
    // ...
}

可以看到下图中所有与文章相关的api都被分配到post下 NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

@ApiProperty()

该方法常用于 *.dto.ts*.entity.ts文件中,将属性暴漏给Swagger.

QueryPostDtosearch属性添加@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中看到请求体了

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

@ApiResponse()

post.entity.tstitle属性加上@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()…)

  • @ApiOkResponseGET 和 DELETE
  • @ApiCreatedResponsePOST 和 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中看到响应体了

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

Swagger CLI Plugin

如果项目中包含很多业务模块UserControllerPostController...,每个业务模块又会涉及很多的 dtoentity文件。如果每个文件都要使用装饰器处理一遍,未免有些过于复杂了。好在 我们可以使用 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文档了

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

导入Insomnia

Insomnia是一款类似Postman的接口管理工具

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

输入swagger的json路径即可

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档

最终一次性导入应用中的所有api, 并且api所需要的请求体都已经填充好了,只需要更改为真实数据即可。

NestJS最佳实践--#9 OpenAPI与Swagger构建API文档