主题
Swagger
使用
@nestjs/swagger生成 OpenAPI 文档
安装与初始化
@nestjs/swagger 从路由和装饰器生成 OpenAPI 文档。应用启动时只初始化一次;文档路径与是否启用应由环境配置控制。
bash
pnpm add @nestjs/swaggerts
import { ValidationPipe } from '@nestjs/common'
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)
app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }))
if (process.env.SWAGGER_ENABLED === 'true') {
const config = new DocumentBuilder()
.setTitle('Hackathon API')
.setDescription('Hackathon 服务接口')
.setVersion('1.0')
.addBearerAuth(undefined, 'bearer')
.build()
const document = SwaggerModule.createDocument(app, config)
SwaggerModule.setup('docs', app, document, {
jsonDocumentUrl: 'docs/openapi.json',
})
}
await app.listen(process.env.PORT ?? 3000)
}
bootstrap()/docs 提供 Swagger UI,/docs/openapi.json 可供客户端生成或契约检查使用。生产环境仅在确有需要时开启,并通过网关、VPN 或认证限制访问;不要将内部管理接口默认暴露到公网。
md
SWAGGER_ENABLED=trueController 元数据
按资源为 Controller 添加 tag、操作说明、认证要求和主要响应。认证方案名称必须与 addBearerAuth() 的第二个参数一致。
ts
import { Controller, Get, NotFoundException, Param } from '@nestjs/common'
import { ApiBearerAuth, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'
@ApiTags('users')
@ApiBearerAuth('bearer')
@Controller('users')
export class UsersController {
@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 中的安全声明仍应与实际路由保持一致。
DTO Schema
运行时反射无法完整保留 TypeScript 的类型信息。为请求和响应 DTO 标注字段、示例和可选性;数组、泛型、联合类型等无法自动推断时显式声明类型。
ts
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import { IsEmail, IsOptional, IsString, MinLength } from 'class-validator'
export class CreateUserDto {
@ApiProperty({ example: 'vfan@example.com' })
@IsEmail()
email: string
@ApiProperty({ minLength: 8 })
@MinLength(8)
password: string
@ApiPropertyOptional({ example: 'Vfan' })
@IsOptional()
@IsString()
nickname?: string
}
export class UserResponseDto {
@ApiProperty({ format: 'uuid' })
id: string
@ApiProperty({ example: 'vfan@example.com' })
email: string
}响应 DTO 不应包含 password、refresh token 或内部状态等敏感字段。分页、统一响应体和错误格式需使用对应 DTO 与 @ApiOkResponse()、@ApiBadRequestResponse() 等装饰器明确描述,避免文档和实际返回值不一致。
维护原则
- 路由、DTO 或鉴权方式变更时,同步检查生成的 OpenAPI JSON。
- 用
@ApiQuery()、@ApiParam()补充无法自动推断的参数约束。 - 将生成的 OpenAPI JSON 纳入契约检查或客户端生成流程前,固定接口版本并评估破坏性变更。
