什么是 nestjs-docfy

一个 NestJS 工具层,把 Swagger 装饰器移出控制器,同时不丢失类型信息,也不会生成不同的 OpenAPI 输出。

问题

@nestjs/swagger 文档化的 NestJS 控制器很快就会堆满几十个 @ApiOperation@ApiResponse@ApiBody@ApiTags,以至于路由真正的逻辑最后被埋在文档元数据下面。

解决方案

nestjs-docfy 引入一个简单的约定:每个 *.controller.ts 旁边都有一个 *.controller.docs.ts,装着所有文档内容。这和 Nest 已经在用的 *.spec.ts 是同一套模式。

  • 生成的 OpenAPI 输出完全不变。
  • 类型信息保留:companion 文件会导入控制器类。
  • SwaggerModule.createDocument() 之前,通过 require.cache 完成发现。

前后对比

users.controller.ts
@WithDocs()
@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.users.findOne(id);
  }
}
users.controller.docs.ts
docs(UsersController, {
  classDecorators: [ApiTags('Users')],
  methods: {
    findOne: [
      ApiParam({ name: 'id', type: String }),
      ApiOperation({ summary: 'Get user by id' }),
      ApiResponse({ status: 200, type: UserDto }),
      ApiResponse({ status: 404, description: 'User not found' }),
    ],
  },
});
webpack: true

Companion 文件发现依赖 require.cache,所以在 nest-cli.json 配置了 "webpack": true 的情况下,运行时无法工作。对这类项目,改为注册 CLI 插件:它会在每次构建时自动地从根本上解决这个问题。

什么时候该用

适合以下场景

  • 你的 API 有几十个端点,每个路由有多种响应。
  • 你的团队把 OpenAPI 当作一份有版本管理的契约。
  • 你想要客观的 CI 门禁(最低覆盖率、文档 lint)。
AI-first

配套的包 docfy-ui 会渲染出 API 参考,每个端点都带一个 Copy for AI 按钮,特别适合粘贴进 LLM。