bw-mini-app-server/docs/swagger-api-documentation.md

601 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Swagger API 文档配置指南
## 1. Swagger 基础配置
### 1.1 安装依赖
```bash
pnpm add @nestjs/swagger swagger-ui-express
pnpm add -D @types/swagger-ui-express
```
### 1.2 基础配置文件
```typescript
// 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 统一响应格式
```typescript
// 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 平台枚举定义
```typescript
// 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
```typescript
// 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
```typescript
// 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 通用错误响应
```typescript
// 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装饰器
```typescript
// 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 使用示例
```typescript
// 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 开发环境配置
```typescript
// 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认证测试功能
- 📝 请求/响应示例
- 🧪 在线接口测试功能
- 📊 数据模型定义