Skip to content

Swagger

使用 @nestjs/swagger 生成 OpenAPI 文档

安装与初始化

@nestjs/swagger 从路由和装饰器生成 OpenAPI 文档。应用启动时只初始化一次;文档路径与是否启用应由环境配置控制。

bash
pnpm add @nestjs/swagger
ts
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=true

Controller 元数据

按资源为 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 纳入契约检查或客户端生成流程前,固定接口版本并评估破坏性变更。

参考

基于 MIT 许可发布