Skip to content
第 19 章 后端 ⏱ 12 分钟阅读

第 19 章:Swagger 文档 ​

学习目标 ​

  • 集成 @nestjs/swagger
  • 给 Controller 和 DTO 加注解
  • 用 Swagger UI 调试
  • 避开 3 个文档维护坑

一、安装 ​

bash
pnpm add @nestjs/swagger swagger-ui-express

二、main.ts 启用 ​

typescript
// main.ts
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const config = new DocumentBuilder()
    .setTitle('My API')
    .setDescription('用户/订单 API 文档')
    .setVersion('1.0')
    .addBearerAuth()                                    // JWT 鉴权
    .addTag('users')
    .build();

  const doc = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api/docs', app, doc);             // /api/docs

  await app.listen(3000);
}

访问 http://localhost:3000/api/docs。

三、给 Controller 加注解 ​

typescript
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';

@ApiTags('users')                                       // 分组
@Controller('users')
export class UsersController {
  @Get()
  @ApiOperation({ summary: '用户列表' })
  @ApiResponse({ status: 200, type: [UserDto] })
  list() {}

  @Get(':id')
  @ApiOperation({ summary: '用户详情' })
  @ApiParam({ name: 'id', example: 1 })
  findOne() {}

  @Post()
  @ApiOperation({ summary: '创建用户' })
  @ApiBearerAuth()                                      // 需要 JWT
  @ApiResponse({ status: 201, type: UserDto })
  @ApiResponse({ status: 400, description: '参数错误' })
  create() {}
}

四、给 DTO 加注解 ​

typescript
// users/dto/create-user.dto.ts
import { ApiProperty } from '@nestjs/swagger';

export class CreateUserDto {
  @ApiProperty({ example: 'tom', minLength: 2 })
  username: string;

  @ApiProperty({ example: 'tom@example.com' })
  email: string;

  @ApiProperty({ example: '123456', minLength: 6, writeOnly: true })
  password: string;
}

export class UserDto {
  @ApiProperty({ example: 1 }) id: number;
  @ApiProperty({ example: 'tom' }) username: string;
  @ApiProperty({ example: 'tom@example.com' }) email: string;
}

Swagger UI 会自动展示字段、必填、示例值。

⚠️ 坑 1:DTO 字段没 @ApiProperty() → Swagger 看不到字段类型,文档不完整。

五、枚举 ​

typescript
export enum UserRole {
  Admin = 'admin',
  User = 'user',
}

export class CreateUserDto {
  @ApiProperty({ enum: UserRole, default: UserRole.User })
  role: UserRole;
}

Swagger 会渲染成下拉框。

六、文件上传 ​

typescript
@ApiConsumes('multipart/form-data')
@ApiBody({
  schema: {
    type: 'object',
    properties: {
      file: { type: 'string', format: 'binary' },
      name: { type: 'string' },
    },
  },
})
@Post('upload')
upload(@UploadedFile() file: Express.Multer.File, @Body('name') name: string) {}

七、响应 DTO 嵌套 ​

typescript
export class PaginatedUserDto {
  @ApiProperty({ type: [UserDto] })
  items: UserDto[];

  @ApiProperty({ example: 100 })
  total: number;
}

@Get()
@ApiResponse({ status: 200, type: PaginatedUserDto })
list() {}

八、生成 OpenAPI JSON ​

/api/docs-json 返回 OpenAPI 3.0 JSON,前端可以用它自动生成 client:

bash
curl http://localhost:3000/api/docs-json > openapi.json

# 生成 TS client
npx openapi-typescript-codegen --input openapi.json --output ./client

⚠️ 坑 2:openapi.json 包含业务信息 → 不要公开部署 /api/docs 到外网。

九、模块化分组 ​

typescript
@ApiTags('admin')
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('admin')
export class AdminController {}

不同 Controller 用不同 Tag,Swagger UI 左侧分组。

十、生产环境隐藏 ​

typescript
if (process.env.NODE_ENV !== 'production') {
  SwaggerModule.setup('api/docs', app, doc);
}

⚠️ 坑 3:生产暴露 Swagger UI → 接口清单泄露,可能被滥用。

十一、实战:文档一个完整模块 ​

typescript
@ApiTags('orders')
@ApiBearerAuth()
@Controller('orders')
@UseGuards(JwtAuthGuard)
export class OrdersController {
  @Get()
  @ApiOperation({ summary: '订单列表' })
  @ApiQuery({ name: 'page', required: false, example: 1 })
  @ApiQuery({ name: 'limit', required: false, example: 20 })
  @ApiResponse({ status: 200, type: PaginatedOrdersDto })
  list() {}

  @Post()
  @ApiOperation({ summary: '创建订单' })
  @ApiResponse({ status: 201, type: OrderDto })
  create(@Body() dto: CreateOrderDto) {}
}

十二、本章小结 ​

注解作用
@ApiTags分组
@ApiOperation接口说明
@ApiResponse响应类型
@ApiPropertyDTO 字段
@ApiBearerAuth鉴权标记
@ApiQuery查询参数
@ApiBody请求体 schema

动手练习 ​

  1. 基础:为 UsersController 加完整注解
  2. DTO:为 CreateUserDto 加 @ApiProperty
  3. 分组:用 @ApiTags 把 admin 单独分组

下一章:第 20 章:文件上传 →

本站基于 VitePress 构建 · 由 StackHub 团队维护