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

26 KiB
Raw Blame History

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(`
      ## 功能特性
      - 🔐 统一用户认证 (微信/支付宝/百度/字节跳动等)
      - 🔄 平台数据同步 (数据库异步处理)
      - 🧩 可扩展架构 (支持后续添加支付、推送等功能)
      - 📊 灵活数据存储 (MySQL + JSON)
      
      ## 认证方式
      使用JWT Bearer Token进行API认证
      
      ## AI模板系统
      - 🎨 动态模板管理 (数据库配置 + 代码执行)
      - 🚀 N8n工作流集成 (图片/视频生成)
      - 📊 使用统计分析 (性能监控 + 用户行为)
      - 🎛️ 运营管理后台 (A/B测试 + 个性化推荐)
      
      ## 响应格式
      所有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. AI模板管理 API

7.1 模板数据传输对象

// src/dto/template.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber, IsEnum, IsOptional, IsArray, IsBoolean } from 'class-validator';

export enum TemplateType {
  IMAGE = 'image',
  VIDEO = 'video'
}

export class TemplateListDto {
  @ApiProperty({ description: '模板ID', example: 1 })
  id: number;

  @ApiProperty({ description: '模板代码', example: 'character_figurine_v1' })
  code: string;

  @ApiProperty({ description: '模板名称', example: '人物手办' })
  name: string;

  @ApiProperty({ description: '模板描述', example: '将人物照片制作成精细的角色手办模型' })
  description: string;

  @ApiProperty({ enum: TemplateType, description: '模板类型', example: 'video' })
  templateType: TemplateType;

  @ApiProperty({ description: '积分消耗', example: 28 })
  creditCost: number;

  @ApiProperty({ description: '版本号', example: '1.0.0' })
  version: string;

  @ApiProperty({ description: '输入示例URL', required: false })
  inputExampleUrl?: string;

  @ApiProperty({ description: '输出示例URL', required: false })
  outputExampleUrl?: string;

  @ApiProperty({ type: [String], description: '标签数组', example: ['人物', '手办', '模型'] })
  tags: string[];

  @ApiProperty({ description: '是否启用', example: true })
  isActive: boolean;

  @ApiProperty({ description: '创建时间', example: '2024-01-01T00:00:00Z' })
  createdAt: Date;
}

export class TemplateExecuteDto {
  @ApiProperty({ 
    description: '输入图片URL', 
    example: 'https://cdn.roasmax.cn/upload/3d590851eb584e92aa415a964e93260e.jpg' 
  })
  @IsString()
  imageUrl: string;
}

export class TemplateExecuteResponseDto {
  @ApiProperty({ description: '执行状态', example: true })
  success: boolean;

  @ApiProperty({ description: '生成结果URL(图片模板)', required: false })
  imageUrl?: string;

  @ApiProperty({ description: '生成结果URL(视频模板)', required: false })
  videoUrl?: string;

  @ApiProperty({ description: '缩略图URL', required: false })
  thumbnailUrl?: string;

  @ApiProperty({ description: '任务ID', example: 'req_1704067200_abc123' })
  taskId: string;

  @ApiProperty({ description: '执行耗时(毫秒)', example: 5000 })
  executionTime: number;

  @ApiProperty({ description: '消耗积分', example: 28 })
  creditCost: number;
}

export class TemplateStatsDto {
  @ApiProperty({ description: '总模板数', example: 8 })
  total: number;

  @ApiProperty({ description: '启用模板数', example: 8 })
  enabled: number;

  @ApiProperty({ description: '图片模板数', example: 3 })
  imageTemplates: number;

  @ApiProperty({ description: '视频模板数', example: 5 })
  videoTemplates: number;
}

7.2 模板管理控制器

// src/controllers/template.controller.ts
import { 
  Controller, Get, Post, Param, Body, Query, UseGuards, ParseIntPipe 
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBearerAuth,
  ApiParam,
  ApiQuery
} from '@nestjs/swagger';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { CurrentUser } from '../decorators/current-user.decorator';
import { ApiCommonResponses, ApiAuthResponses } from '../decorators/api-common-responses.decorator';
import { N8nTemplateFactoryService } from '../services/n8n-template-factory.service';
import { TemplateListDto, TemplateExecuteDto, TemplateExecuteResponseDto, TemplateStatsDto } from '../dto/template.dto';

@ApiTags('🎨 AI模板系统')
@Controller('templates')
@ApiCommonResponses()
export class TemplateController {
  constructor(
    private readonly templateFactory: N8nTemplateFactoryService,
  ) {}

  @Get()
  @ApiOperation({
    summary: '获取所有模板列表',
    description: '获取所有可用的AI生成模板支持按类型筛选'
  })
  @ApiQuery({
    name: 'type',
    required: false,
    enum: ['image', 'video'],
    description: '模板类型筛选'
  })
  @ApiResponse({
    status: 200,
    description: '获取成功',
    type: [TemplateListDto]
  })
  async getTemplates(@Query('type') type?: 'image' | 'video') {
    if (type === 'image') {
      return this.templateFactory.getTemplatesByType('image');
    } else if (type === 'video') {
      return this.templateFactory.getTemplatesByType('video');
    }
    return this.templateFactory.getAllTemplates();
  }

  @Get('stats')
  @ApiOperation({
    summary: '获取模板统计信息',
    description: '获取模板总数、类型分布等统计信息'
  })
  @ApiResponse({
    status: 200,
    description: '获取成功',
    type: TemplateStatsDto
  })
  async getTemplateStats() {
    const allTemplates = await this.templateFactory.getAllTemplates();
    const imageTemplates = allTemplates.filter(t => t.templateType === 'image');
    const videoTemplates = allTemplates.filter(t => t.templateType === 'video');
    
    return {
      total: allTemplates.length,
      enabled: allTemplates.filter(t => t.isActive).length,
      imageTemplates: imageTemplates.length,
      videoTemplates: videoTemplates.length,
    };
  }

  @Get(':templateId')
  @ApiOperation({
    summary: '获取模板详情',
    description: '根据模板ID获取详细信息'
  })
  @ApiParam({
    name: 'templateId',
    description: '模板ID',
    example: 1
  })
  @ApiResponse({
    status: 200,
    description: '获取成功',
    type: TemplateListDto
  })
  async getTemplateById(@Param('templateId', ParseIntPipe) templateId: number) {
    return this.templateFactory.getTemplateById(templateId);
  }

  @Get('code/:templateCode')
  @ApiOperation({
    summary: '通过代码获取模板详情',
    description: '根据模板代码获取详细信息'
  })
  @ApiParam({
    name: 'templateCode',
    description: '模板代码',
    example: 'character_figurine_v1'
  })
  @ApiResponse({
    status: 200,
    description: '获取成功',
    type: TemplateListDto
  })
  async getTemplateByCode(@Param('templateCode') templateCode: string) {
    return this.templateFactory.getTemplateByCode(templateCode);
  }

  @Post(':templateId/execute')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiAuthResponses()
  @ApiOperation({
    summary: '执行模板生成',
    description: '根据模板ID执行AI生成任务支持图片和视频生成'
  })
  @ApiParam({
    name: 'templateId',
    description: '模板ID',
    example: 1
  })
  @ApiResponse({
    status: 200,
    description: '执行成功',
    type: TemplateExecuteResponseDto
  })
  @ApiResponse({
    status: 400,
    description: '参数错误',
    schema: {
      example: {
        code: 400,
        message: '输入图片URL不能为空',
        data: null
      }
    }
  })
  @ApiResponse({
    status: 402,
    description: '积分不足',
    schema: {
      example: {
        code: 402,
        message: '积分不足,当前余额: 10需要: 28',
        data: null
      }
    }
  })
  async executeTemplate(
    @Param('templateId', ParseIntPipe) templateId: number,
    @Body() executeDto: TemplateExecuteDto,
    @CurrentUser() user: any
  ) {
    const startTime = Date.now();
    
    // 获取模板配置
    const templateConfig = await this.templateFactory.getTemplateById(templateId);
    
    // 创建动态模板实例并执行
    let template;
    if (templateConfig.templateType === 'image') {
      template = await this.templateFactory.createImageTemplate(templateId);
    } else {
      template = await this.templateFactory.createVideoTemplate(templateId);
    }

    const result = await template.execute(executeDto.imageUrl);
    const executionTime = Date.now() - startTime;

    return {
      success: true,
      imageUrl: templateConfig.templateType === 'image' ? result : undefined,
      videoUrl: templateConfig.templateType === 'video' ? result : undefined,
      taskId: `req_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
      executionTime,
      creditCost: templateConfig.creditCost
    };
  }

  @Post('code/:templateCode/execute')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiAuthResponses()
  @ApiOperation({
    summary: '通过代码执行模板',
    description: '根据模板代码执行AI生成任务支持图片和视频生成'
  })
  @ApiParam({
    name: 'templateCode',
    description: '模板代码',
    example: 'character_figurine_v1'
  })
  @ApiResponse({
    status: 200,
    description: '执行成功',
    type: TemplateExecuteResponseDto
  })
  async executeTemplateByCode(
    @Param('templateCode') templateCode: string,
    @Body() executeDto: TemplateExecuteDto,
    @CurrentUser() user: any
  ) {
    const startTime = Date.now();
    
    // 创建动态模板实例并执行
    const template = await this.templateFactory.createTemplateByCode(templateCode);
    const result = await template.execute(executeDto.imageUrl);
    const executionTime = Date.now() - startTime;

    return {
      success: true,
      imageUrl: template.templateType === 'image' ? result : undefined,
      videoUrl: template.templateType === 'video' ? result : undefined,
      taskId: `req_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
      executionTime,
      creditCost: template.creditCost
    };
  }
}

7.3 API使用示例

获取所有模板

curl -X GET "http://localhost:3000/api/templates" \
  -H "accept: application/json"

响应示例:

{
  "code": 200,
  "message": "success",
  "data": [
    {
      "id": 1,
      "code": "character_figurine_v1",
      "name": "人物手办",
      "description": "将人物照片制作成精细的角色手办模型,展示在收藏家房间中,并生成抚摸手办的视频",
      "templateType": "video",
      "creditCost": 28,
      "version": "1.0.0",
      "inputExampleUrl": "https://cdn.roasmax.cn/upload/3d590851eb584e92aa415a964e93260e.jpg",
      "outputExampleUrl": "https://file.302.ai/gpt/imgs/20250828/2283106b31faf2066e1a72d955f65bca.jpg",
      "tags": ["人物", "手办", "模型", "收藏", "PVC", "角色模型", "视频生成"],
      "isActive": true,
      "createdAt": "2024-01-01T00:00:00Z"
    }
  ]
}

执行模板生成

curl -X POST "http://localhost:3000/api/templates/1/execute" \
  -H "accept: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "imageUrl": "https://cdn.roasmax.cn/upload/3d590851eb584e92aa415a964e93260e.jpg"
  }'

响应示例:

{
  "code": 200,
  "message": "success",
  "data": {
    "success": true,
    "videoUrl": "https://n8n.bowongai.com/files/generated_video_abc123.mp4",
    "taskId": "req_1704067200_abc123",
    "executionTime": 5000,
    "creditCost": 28
  }
}

7.4 错误处理

// 常见错误响应
export const TemplateApiErrors = {
  TEMPLATE_NOT_FOUND: {
    code: 404,
    message: '模板不存在',
    data: null
  },
  INSUFFICIENT_CREDITS: {
    code: 402,
    message: '积分不足',
    data: { required: 28, current: 10 }
  },
  INVALID_IMAGE_URL: {
    code: 400,
    message: '无效的图片URL',
    data: null
  },
  TEMPLATE_EXECUTION_FAILED: {
    code: 500,
    message: 'AI生成失败请稍后重试',
    data: null
  },
  TEMPLATE_DISABLED: {
    code: 403,
    message: '模板已禁用',
    data: null
  }
};

8. 环境配置

8.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();

9. 访问API文档

启动应用后访问以下地址查看API文档

API文档包含

  • 📋 完整的接口列表和参数说明
  • 🔐 JWT认证测试功能
  • 📝 请求/响应示例
  • 🧪 在线接口测试功能
  • 📊 数据模型定义
  • 🎨 AI模板系统接口 (支持图片/视频生成)
  • 💾 动态模板配置管理
  • 📈 模板使用统计和监控