NestJS中@nestjs/swagger配置API文档的最佳实践
@nestjs/swagger 静态配置文件说明
@nestjs/swagger 没有默认的静态配置文件扫描路径,你把写好的 swagger.json 或者 swagger.yaml 随便放项目哪个目录,框架都不会主动读取生效。它的默认逻辑是启动时动态扫描控制器、路由、装饰器元数据自动生成文档结构。
如果你确实要使用本地维护的静态swagger文件,可以手动写读取逻辑加载,比如把静态文件放在 src/config/swagger/ 目录下,初始化Swagger时跳过自动生成步骤,直接读取文件内容传入即可:
// main.ts Swagger初始化片段 import * as fs from 'fs'; import * as path from 'path'; import { SwaggerModule } from '@nestjs/swagger'; // 读取本地静态swagger文件 const staticSwaggerDoc = JSON.parse( fs.readFileSync(path.join(process.cwd(), 'src/config/swagger/swagger.json'), 'utf-8') ); SwaggerModule.setup('api/docs', app, staticSwaggerDoc);
不推荐这种方式:静态文件和实际接口代码完全解耦,后续改接口逻辑、改参数时很容易忘记同步文档,时间长了文档和实际接口完全对不上,维护成本极高。
减少重复配置的最佳实践
不用逐接口堆装饰器写配置,用下面几种方式可以覆盖90%的文档场景,重复代码量能降到最低:
- 全局统一配置通用规则
通用的鉴权方式、接口公共说明、全局通用错误码,全部在Swagger初始化阶段统一配置,不用每个接口单独写。比如批量给所有接口追加401、403、500这类通用错误响应:import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; const swaggerConfig = new DocumentBuilder() .setTitle('业务系统API文档') .setVersion('1.0') .addBearerAuth() // 全局统一添加JWT鉴权请求头 .build(); const document = SwaggerModule.createDocument(app, swaggerConfig); // 遍历所有接口批量追加通用响应 Object.values(document.paths).forEach(pathItem => { Object.values(pathItem).forEach(operation => { if (typeof operation !== 'object' || !operation.responses) return; operation.responses['401'] = { description: '登录状态已失效,请重新登录' }; operation.responses['403'] = { description: '当前账号无该接口访问权限' }; operation.responses['500'] = { description: '服务内部异常' }; }); }); SwaggerModule.setup('api/docs', app, document); - 封装自定义装饰器复用重复逻辑
对于某一类通用的接口配置(比如分页查询参数、增删改查的通用响应、固定的接口描述结构),用applyDecorators把多个Swagger装饰器打包成一个自定义装饰器,用的时候直接加在接口上就行,不用重复写一堆装饰器:import { applyDecorators } from '@nestjs/common'; import { ApiOperation, ApiQuery, ApiResponse } from '@nestjs/swagger'; // 封装分页接口通用配置装饰器 export function ApiPagination(summary: string) { return applyDecorators( ApiOperation({ summary }), ApiQuery({ name: 'page', type: Number, required: false, description: '页码,默认值1' }), ApiQuery({ name: 'pageSize', type: Number, required: false, description: '每页条数,默认值10' }), ApiResponse({ status: 400, description: '分页参数格式错误' }) ); } // 控制器中使用 @Get('user/list') @ApiPagination('查询用户列表') getUserList() { return this.userService.getList(); } - DTO复用+CLI插件自动生成字段文档
所有请求参数、响应结构都用TS类定义为DTO,不要在接口上零散写字段说明。开启@nestjs/swagger的CLI插件后,框架会自动扫描DTO的TS类型、注释、class-validator校验规则,自动生成字段的文档说明,连@ApiProperty装饰器都不用手动写。
首先在nest-cli.json中开启插件:
开启后写DTO只要加普通TS注释就行,Swagger会自动识别:{ "collection": "@nestjs/schematics", "sourceRoot": "src", "compilerOptions": { "plugins": [ { "name": "@nestjs/swagger", "options": { "classValidatorShim": true, "introspectComments": true } } ] } }
通用的分页响应、列表响应这类结构,写一次基础DTO,所有业务接口直接继承复用就行,不用重复定义字段。export class UserDto { /** 用户ID */ id: number; /** 用户昵称 */ nickname: string; /** 账号注册时间 */ createTime: Date; }
入门实用建议
- 别一开始就折腾静态swagger文件,NestJS体系下动态生成文档的方式和代码绑定更紧,只要改代码的时候同步更新DTO,文档不会和实际接口脱节。
- 配置遵循公共逻辑全局收,业务逻辑局部写的原则:通用错误码、通用参数、鉴权这类全接口共用的配置全放到初始化逻辑里,只有某个接口特有的错误码、特殊参数才单独在接口上配置。
- 用
@ApiTags()按业务模块给控制器打标签,Swagger页面会自动把同模块接口归组,查找调试都方便。 - 不用为了文档“看起来全”写一堆无意义的描述,比如200响应默认就是“请求成功”,不用每个接口重复写,只把特殊的业务规则、错误场景写清楚就行。
内容的提问来源于stack exchange,提问作者diabeetus-fairy
相关产品推荐
相关产品推荐

