主题
集成 Swagger
@nestjs/swagger 根据 Controller、路由参数和 DTO 生成 OpenAPI 文档,并提供可交互的 Swagger UI。
1. 安装依赖
安装 NestJS 官方 Swagger 模块:
bash
pnpm add @nestjs/swagger2. 配置启用条件
Swagger 文档可能暴露接口结构和调试能力,是否启用应由环境变量控制:
bash
SWAGGER_ENABLED=true生产环境仅在确有需要时开启,并通过网关、VPN 或认证限制访问。
3. 在应用入口初始化
在 main.ts 中完成以下操作:
- 使用
DocumentBuilder定义文档基本信息和认证方案。 - 使用
SwaggerModule.createDocument()生成 OpenAPI 文档。 - 使用
SwaggerModule.setup()挂载 Swagger UI 和 JSON 文档。
ts
import { NestFactory } from '@nestjs/core'
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'
import { AppModule } from './app.module'
async function bootstrap() {
const app = await NestFactory.create(AppModule)
if (process.env.SWAGGER_ENABLED === 'true') {
const config = new DocumentBuilder()
.setTitle('Hackathon API')
.setDescription('Hackathon 服务接口')
.setVersion('1.0')
.addBearerAuth(undefined, 'bearer')
.build()
const documentFactory = () => SwaggerModule.createDocument(app, config)
SwaggerModule.setup('docs', app, documentFactory, {
jsonDocumentUrl: 'docs/openapi.json',
})
}
await app.listen(process.env.PORT ?? 3000)
}
void bootstrap()addBearerAuth(undefined, 'bearer') 注册名为 bearer 的 Bearer Token 认证方案。后续使用 @ApiBearerAuth('bearer') 时,名称必须保持一致。
4. 描述 DTO Schema
TypeScript 的运行时反射无法获得完整的字段信息。使用 @ApiProperty() 和 @ApiPropertyOptional() 描述请求、响应 DTO 的字段、格式和示例:
ts
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
export class CreateUserDto {
@ApiProperty({ example: 'vfan@example.com' })
email: string
@ApiProperty({ minLength: 8 })
password: string
@ApiPropertyOptional({ example: 'Vfan' })
nickname?: string
}
export class UserResponseDto {
@ApiProperty({ format: 'uuid' })
id: string
@ApiProperty({ example: 'vfan@example.com' })
email: string
}响应 DTO 不应包含密码、Refresh Token 或内部状态等敏感字段。数组、泛型、联合类型等无法自动推断时,需要显式声明 Schema。
常用装饰器:
| 装饰器 | 用途 |
|---|---|
@ApiProperty() | 描述必填字段的类型、格式、示例和约束 |
@ApiPropertyOptional() | 描述可选字段,等同于设置 required: false |
@ApiHideProperty() | 从生成的 OpenAPI Schema 中隐藏指定字段 |
@ApiExtraModels() | 注册未被 Controller 直接引用的额外 DTO 模型 |
5. 标注 Controller
为 Controller 添加资源分组,并为路由声明操作说明、认证要求和主要响应:
ts
import { Controller, Get, NotFoundException, Param } from '@nestjs/common'
import { ApiBearerAuth, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'
import { UserResponseDto } from './dto/user-response.dto'
import { UsersService } from './users.service'
@ApiTags('users')
@ApiBearerAuth('bearer')
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get(':id')
@ApiOperation({ summary: '查询用户' })
@ApiOkResponse({ type: UserResponseDto })
@ApiNotFoundResponse({ description: '用户不存在' })
async findOne(@Param('id') id: string): Promise<UserResponseDto> {
const user = await this.usersService.findOne(id)
if (!user) throw new NotFoundException('用户不存在')
return user
}
}公开端点不添加 @ApiBearerAuth();当项目使用全局 Guard 时,Swagger 中的安全声明仍应与实际路由保持一致。
常用装饰器:
| 装饰器 | 用途 |
|---|---|
@ApiTags() | 对 Controller 进行资源分组 |
@ApiOperation() | 描述接口用途 |
@ApiBearerAuth() | 声明接口需要 Bearer Token |
@ApiOkResponse() | 描述成功响应 |
@ApiBadRequestResponse() | 描述参数错误响应 |
@ApiParam() | 补充路径参数约束 |
@ApiQuery() | 补充查询参数约束 |
6. 启动并检查文档
bash
pnpm start:dev应用启动后访问:
- Swagger UI:
http://localhost:3000/docs - OpenAPI JSON:
http://localhost:3000/docs/openapi.json
Swagger UI 应能显示 Controller 路由、请求参数、DTO Schema、响应类型和认证入口。若启用了全局路由前缀,Swagger 文档路径默认不自动添加该前缀;需要保持一致时,在 SwaggerModule.setup() 的选项中设置 useGlobalPrefix: true。
维护原则
- 路由、DTO 或鉴权方式变更时,同步检查生成的 OpenAPI JSON。
- 用
@ApiQuery()、@ApiParam()补充无法自动推断的参数约束。 - 将生成的 OpenAPI JSON 纳入契约检查或客户端生成流程前,固定接口版本并评估破坏性变更。
