14 KiB
14 KiB
Swagger API 文档配置指南
1. Swagger 基础配置
1.1 安装依赖
pnpm add @nestjs/swagger swagger-ui-express
pnpm add -D @types/swagger-ui-express
1.2 基础配置文件
// src/config/swagger.config.ts
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { INestApplication } from '@nestjs/common';
export function setupSwagger(app: INestApplication): void {
const config = new DocumentBuilder()
.setTitle('多平台小程序统一后台API')
.setDescription(`
## 功能特性
- 🔐 统一用户认证 (微信/支付宝/百度/字节跳动等)
- 🔄 平台数据同步 (RabbitMQ异步处理)
- 🧩 可扩展架构 (支持后续添加支付、推送等功能)
- 📊 灵活数据存储 (PostgreSQL + JSONB)
## 认证方式
使用JWT Bearer Token进行API认证
## 响应格式
所有API响应都遵循统一格式:
\`\`\`json
{
"code": 200,
"message": "success",
"data": {},
"timestamp": 1703001000000,
"traceId": "trace-uuid"
}
\`\`\`
`)
.setVersion('1.0.0')
.setContact('开发团队', 'https://example.com', 'dev@example.com')
.setLicense('MIT', 'https://opensource.org/licenses/MIT')
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
name: 'JWT',
description: 'Enter JWT token',
in: 'header',
},
'JWT-auth',
)
.addTag('🔐 用户管理', '用户注册、登录、信息管理')
.addTag('🔄 平台适配', '各平台特定接口和数据同步')
.addTag('🧩 扩展服务', '预留的扩展功能接口')
.addTag('📊 数据统计', '业务数据统计和分析')
.addServer('http://localhost:3000', '开发环境')
.addServer('https://api-dev.example.com', '测试环境')
.addServer('https://api.example.com', '生产环境')
.build();
const document = SwaggerModule.createDocument(app, config, {
operationIdFactory: (controllerKey: string, methodKey: string) => methodKey,
});
SwaggerModule.setup('api/docs', app, document, {
swaggerOptions: {
persistAuthorization: true,
tagsSorter: 'alpha',
operationsSorter: 'alpha',
docExpansion: 'none',
filter: true,
showRequestDuration: true,
},
customSiteTitle: '多平台API文档',
customfavIcon: '/favicon.ico',
customJs: [
'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-bundle.min.js',
],
customCssUrl: [
'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui.min.css',
],
});
}
2. 通用DTO定义
2.1 统一响应格式
// src/dto/common-response.dto.ts
import { ApiProperty } from '@nestjs/swagger';
export class CommonResponseDto<T = any> {
@ApiProperty({ description: '响应状态码', example: 200 })
code: number;
@ApiProperty({ description: '响应消息', example: 'success' })
message: string;
@ApiProperty({ description: '响应数据' })
data: T;
@ApiProperty({ description: '时间戳', example: 1703001000000 })
timestamp: number;
@ApiProperty({ description: '追踪ID', example: 'trace-uuid-123' })
traceId: string;
}
export class PaginationDto {
@ApiProperty({ description: '页码', example: 1, minimum: 1 })
page: number;
@ApiProperty({ description: '每页数量', example: 10, minimum: 1, maximum: 100 })
limit: number;
}
export class PaginationResponseDto<T = any> {
@ApiProperty({ description: '数据列表' })
items: T[];
@ApiProperty({ description: '总数量', example: 100 })
total: number;
@ApiProperty({ description: '当前页码', example: 1 })
page: number;
@ApiProperty({ description: '每页数量', example: 10 })
limit: number;
@ApiProperty({ description: '总页数', example: 10 })
totalPages: number;
}
2.2 平台枚举定义
// src/dto/platform.dto.ts
import { ApiProperty } from '@nestjs/swagger';
export enum PlatformType {
WECHAT = 'wechat',
ALIPAY = 'alipay',
BAIDU = 'baidu',
BYTEDANCE = 'bytedance',
JD = 'jd',
QQ = 'qq',
FEISHU = 'feishu',
KUAISHOU = 'kuaishou',
H5 = 'h5',
RN = 'rn'
}
export const PlatformDescriptions = {
[PlatformType.WECHAT]: '微信小程序',
[PlatformType.ALIPAY]: '支付宝小程序',
[PlatformType.BAIDU]: '百度智能小程序',
[PlatformType.BYTEDANCE]: '字节跳动小程序',
[PlatformType.JD]: '京东小程序',
[PlatformType.QQ]: 'QQ小程序',
[PlatformType.FEISHU]: '飞书小程序',
[PlatformType.KUAISHOU]: '快手小程序',
[PlatformType.H5]: 'H5应用',
[PlatformType.RN]: 'React Native应用',
};
3. 用户管理API文档
3.1 用户登录DTO
// src/dto/user.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsOptional, IsObject } from 'class-validator';
import { PlatformType } from './platform.dto';
export class UserLoginDto {
@ApiProperty({
description: '平台类型',
enum: PlatformType,
example: PlatformType.WECHAT,
enumName: 'PlatformType',
})
@IsEnum(PlatformType)
platform: PlatformType;
@ApiProperty({
description: '平台授权码/临时登录凭证',
example: '081234567890abcdef',
minLength: 1,
maxLength: 200,
})
@IsString()
code: string;
@ApiProperty({
description: '加密用户数据 (微信小程序专用)',
required: false,
example: 'encrypted_user_data_string',
})
@IsOptional()
@IsString()
encryptedData?: string;
@ApiProperty({
description: '加密向量 (微信小程序专用)',
required: false,
example: 'iv_string',
})
@IsOptional()
@IsString()
iv?: string;
@ApiProperty({
description: '额外的平台特定数据',
required: false,
type: 'object',
example: { sessionKey: 'session_key_value' },
})
@IsOptional()
@IsObject()
extra?: Record<string, any>;
}
export class UserInfoDto {
@ApiProperty({ description: '用户ID', example: 'user-uuid-123' })
id: string;
@ApiProperty({ description: '统一用户ID', example: 'unified-user-123' })
unifiedUserId: string;
@ApiProperty({ description: '用户昵称', example: '张三' })
nickname: string;
@ApiProperty({
description: '头像URL',
example: 'https://example.com/avatar.jpg'
})
avatarUrl: string;
@ApiProperty({
description: '手机号',
example: '13800138000',
required: false
})
phone?: string;
@ApiProperty({
description: '邮箱',
example: 'user@example.com',
required: false
})
email?: string;
@ApiProperty({ description: '用户状态', example: 1 })
status: number;
@ApiProperty({ description: '创建时间', example: '2023-12-01T10:00:00Z' })
createdAt: Date;
@ApiProperty({ description: '更新时间', example: '2023-12-01T10:00:00Z' })
updatedAt: Date;
}
export class UserLoginResponseDto {
@ApiProperty({
description: 'JWT访问令牌',
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
})
token: string;
@ApiProperty({
description: '刷新令牌',
example: 'refresh_token_string_here',
})
refreshToken: string;
@ApiProperty({
description: '用户信息',
type: UserInfoDto,
})
userInfo: UserInfoDto;
@ApiProperty({
description: '平台特定数据',
type: 'object',
required: false,
example: { openid: 'wx_openid_123' },
})
platformSpecific?: Record<string, any>;
}
4. 扩展服务API文档
4.1 扩展数据相关DTO
// src/dto/extension.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsOptional, IsObject } from 'class-validator';
import { PlatformType } from './platform.dto';
export class CreateExtensionDataDto {
@ApiProperty({
description: '用户ID',
example: 'user-uuid-123',
})
@IsString()
userId: string;
@ApiProperty({
description: '平台类型',
enum: PlatformType,
example: PlatformType.WECHAT,
})
@IsEnum(PlatformType)
platform: PlatformType;
@ApiProperty({
description: '数据类型',
example: 'custom',
maxLength: 50,
})
@IsString()
dataType: string;
@ApiProperty({
description: '外部引用ID',
required: false,
example: 'ref-123456',
maxLength: 100,
})
@IsOptional()
@IsString()
referenceId?: string;
@ApiProperty({
description: '扩展数据内容',
type: 'object',
example: {
customField1: 'value1',
customField2: 'value2',
settings: { enabled: true }
},
})
@IsObject()
data: Record<string, any>;
@ApiProperty({
description: '元数据',
required: false,
type: 'object',
example: { source: 'api', version: '1.0' },
})
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
}
export class ExtensionDataResponseDto {
@ApiProperty({ description: '扩展数据ID', example: 'ext-uuid-123' })
id: string;
@ApiProperty({ description: '用户ID', example: 'user-uuid-123' })
userId: string;
@ApiProperty({
description: '平台类型',
enum: PlatformType,
example: PlatformType.WECHAT,
})
platform: PlatformType;
@ApiProperty({ description: '数据类型', example: 'custom' })
dataType: string;
@ApiProperty({ description: '外部引用ID', example: 'ref-123456' })
referenceId: string;
@ApiProperty({
description: '扩展数据内容',
type: 'object',
})
data: Record<string, any>;
@ApiProperty({
description: '元数据',
type: 'object',
})
metadata: Record<string, any>;
@ApiProperty({ description: '状态', example: 'active' })
status: string;
@ApiProperty({ description: '创建时间', example: '2023-12-01T10:00:00Z' })
createdAt: Date;
@ApiProperty({ description: '更新时间', example: '2023-12-01T10:00:00Z' })
updatedAt: Date;
}
5. 错误响应文档
5.1 通用错误响应
// src/dto/error-response.dto.ts
import { ApiProperty } from '@nestjs/swagger';
export class ErrorResponseDto {
@ApiProperty({ description: '错误状态码', example: 400 })
code: number;
@ApiProperty({ description: '错误消息', example: '请求参数错误' })
message: string;
@ApiProperty({ description: '错误数据', example: null })
data: null;
@ApiProperty({ description: '时间戳', example: 1703001000000 })
timestamp: number;
@ApiProperty({ description: '追踪ID', example: 'trace-uuid-123' })
traceId: string;
@ApiProperty({
description: '详细错误信息',
required: false,
example: ['字段验证失败'],
})
details?: string[];
}
// 常用错误响应示例
export const CommonErrorResponses = {
BadRequest: {
status: 400,
description: '请求参数错误',
type: ErrorResponseDto,
},
Unauthorized: {
status: 401,
description: '未授权访问',
type: ErrorResponseDto,
},
Forbidden: {
status: 403,
description: '禁止访问',
type: ErrorResponseDto,
},
NotFound: {
status: 404,
description: '资源不存在',
type: ErrorResponseDto,
},
InternalServerError: {
status: 500,
description: '服务器内部错误',
type: ErrorResponseDto,
},
};
6. 装饰器使用示例
6.1 Controller装饰器
// src/decorators/api-common-responses.decorator.ts
import { applyDecorators } from '@nestjs/common';
import { ApiResponse } from '@nestjs/swagger';
import { CommonErrorResponses } from '../dto/error-response.dto';
export function ApiCommonResponses() {
return applyDecorators(
ApiResponse(CommonErrorResponses.BadRequest),
ApiResponse(CommonErrorResponses.Unauthorized),
ApiResponse(CommonErrorResponses.InternalServerError),
);
}
export function ApiAuthResponses() {
return applyDecorators(
ApiResponse(CommonErrorResponses.Unauthorized),
ApiResponse(CommonErrorResponses.Forbidden),
);
}
6.2 使用示例
// src/controllers/user.controller.ts
import { Controller, Post, Body, Get, UseGuards } from '@nestjs/common';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiBearerAuth,
} from '@nestjs/swagger';
import { ApiCommonResponses, ApiAuthResponses } from '../decorators/api-common-responses.decorator';
@ApiTags('🔐 用户管理')
@Controller('users')
@ApiCommonResponses()
export class UserController {
@Post('login')
@ApiOperation({
summary: '用户登录',
description: '支持多平台用户登录,返回JWT令牌和用户信息',
})
@ApiResponse({
status: 200,
description: '登录成功',
type: UserLoginResponseDto,
})
async login(@Body() loginDto: UserLoginDto) {
return this.userService.login(loginDto);
}
@Get('profile')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth('JWT-auth')
@ApiAuthResponses()
@ApiOperation({
summary: '获取用户信息',
description: '获取当前登录用户的详细信息',
})
@ApiResponse({
status: 200,
description: '获取成功',
type: UserInfoDto,
})
async getProfile(@CurrentUser() user: any) {
return this.userService.getProfile(user.id);
}
}
7. 环境配置
7.1 开发环境配置
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
import { setupSwagger } from './config/swagger.config';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 全局验证管道
app.useGlobalPipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}));
// API前缀
app.setGlobalPrefix('api/v1');
// CORS配置
app.enableCors({
origin: process.env.NODE_ENV === 'production'
? ['https://example.com']
: true,
credentials: true,
});
// 仅在非生产环境启用Swagger
if (process.env.NODE_ENV !== 'production') {
setupSwagger(app);
}
const port = process.env.PORT || 3000;
await app.listen(port);
console.log('🚀 应用启动成功!');
console.log(`📖 API文档地址: http://localhost:${port}/api/docs`);
}
bootstrap();
8. 访问API文档
启动应用后,访问以下地址查看API文档:
- 开发环境: http://localhost:3000/api/docs
- JSON格式: http://localhost:3000/api/docs-json
- YAML格式: http://localhost:3000/api/docs-yaml
API文档包含:
- 📋 完整的接口列表和参数说明
- 🔐 JWT认证测试功能
- 📝 请求/响应示例
- 🧪 在线接口测试功能
- 📊 数据模型定义