第 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 | 响应类型 |
@ApiProperty | DTO 字段 |
@ApiBearerAuth | 鉴权标记 |
@ApiQuery | 查询参数 |
@ApiBody | 请求体 schema |
动手练习
- 基础:为 UsersController 加完整注解
- DTO:为 CreateUserDto 加 @ApiProperty
- 分组:用 @ApiTags 把 admin 单独分组
下一章:第 20 章:文件上传 →