Files
photography/backend/docs/API_DOCUMENTATION.md
xujiang 0ddde92a3c feat: 完成API测试、生产环境配置和文档编写
## 🧪 API测试系统完善
- 创建完整的单元测试套件 (tests/unit_test.go)
  - 认证流程、CRUD操作、文件上传测试
  - 中间件、错误处理、性能测试
- 创建集成测试套件 (tests/integration_test.go)
  - 业务流程、数据一致性、并发测试
- 创建综合API测试 (test_api_comprehensive.http)
  - 92个测试场景,覆盖所有API端点
- 更新Makefile添加测试命令
  - test-unit, test-integration, test-api, test-cover, test-bench

## 🗄️ 生产环境数据库配置
- Docker Compose生产环境配置 (configs/docker/docker-compose.prod.yml)
  - PostgreSQL 16 + Redis 7 + Nginx + 监控栈
- 数据库初始化脚本 (configs/docker/init-db.sql)
  - 完整表结构、索引优化、触发器、视图
- 生产环境配置脚本 (scripts/production-db-setup.sh)
  - 自动化配置、连接池、备份策略、监控

## 📚 API文档完善
- 完整的API文档 (docs/API_DOCUMENTATION.md)
  - 详细接口说明、请求响应示例
  - 认证流程、错误处理、性能优化
  - SDK支持、部署指南、安全考虑
- 包含cURL示例和Postman Collection支持

## 📊 项目进度
- 总进度: 50.0% → 57.5%
- 中优先级任务: 55% → 70%
- 并行完成3个重要任务,显著提升项目完成度

## 🎯 技术成果
- 测试覆盖率大幅提升,支持自动化测试
- 生产环境就绪,支持Docker部署
- 完整的API文档,便于前后端协作
- 性能优化和监控配置,确保生产稳定性
2025-07-11 14:10:43 +08:00

17 KiB
Raw Permalink Blame History

Photography Portfolio API Documentation

📋 API 概览

Photography Portfolio API 是一个基于 go-zero 框架的 RESTful API 服务,提供完整的摄影作品集管理功能。

基本信息

  • API 版本: v1.0.0
  • 基础URL: https://api.photography.iriver.top/api/v1
  • 开发环境: http://localhost:8080/api/v1
  • 认证方式: JWT Bearer Token
  • 数据格式: JSON
  • 字符编码: UTF-8

响应格式

所有 API 响应都遵循统一的格式:

{
  "code": 200,
  "message": "success",
  "data": {
    // 实际数据
  }
}

状态码

HTTP状态码 业务码 说明
200 200 请求成功
400 400 请求参数错误
401 401 未授权
403 403 权限不足
404 404 资源不存在
500 500 服务器内部错误

错误响应

{
  "code": 400,
  "message": "参数验证失败",
  "data": null
}

🔐 认证接口

用户注册

接口地址: POST /auth/register

请求参数:

{
  "username": "string",    // 用户名3-20个字符
  "email": "string",       // 邮箱地址
  "password": "string"     // 密码6-20个字符
}

响应示例:

{
  "code": 200,
  "message": "注册成功",
  "data": {
    "user": {
      "id": 1,
      "username": "johndoe",
      "email": "john@example.com",
      "avatar": "",
      "status": 1,
      "created_at": "2024-01-10T10:30:00Z"
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}

cURL 示例:

curl -X POST "http://localhost:8080/api/v1/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "johndoe",
    "email": "john@example.com",
    "password": "password123"
  }'

用户登录

接口地址: POST /auth/login

请求参数:

{
  "username": "string",    // 用户名或邮箱
  "password": "string"     // 密码
}

响应示例:

{
  "code": 200,
  "message": "登录成功",
  "data": {
    "user": {
      "id": 1,
      "username": "johndoe",
      "email": "john@example.com",
      "avatar": "/uploads/avatars/1.jpg",
      "status": 1
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_at": "2024-01-11T10:30:00Z"
  }
}

cURL 示例:

curl -X POST "http://localhost:8080/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "johndoe",
    "password": "password123"
  }'

👥 用户管理接口

获取用户列表

接口地址: GET /users

请求头: Authorization: Bearer <token>

查询参数:

  • page: 页码,默认 1
  • limit: 每页数量,默认 10最大 100
  • status: 用户状态,可选值 0(禁用) 1(正常)
  • keyword: 搜索关键词

响应示例:

{
  "code": 200,
  "message": "success",
  "data": {
    "users": [
      {
        "id": 1,
        "username": "johndoe",
        "email": "john@example.com",
        "avatar": "/uploads/avatars/1.jpg",
        "status": 1,
        "created_at": "2024-01-10T10:30:00Z",
        "updated_at": "2024-01-10T10:30:00Z"
      }
    ],
    "total": 50,
    "page": 1,
    "limit": 10,
    "pages": 5
  }
}

cURL 示例:

curl -X GET "http://localhost:8080/api/v1/users?page=1&limit=10" \
  -H "Authorization: Bearer <your-token>"

获取用户详情

接口地址: GET /users/{id}

请求头: Authorization: Bearer <token>

路径参数:

  • id: 用户ID

响应示例:

{
  "code": 200,
  "message": "success",
  "data": {
    "id": 1,
    "username": "johndoe",
    "email": "john@example.com",
    "avatar": "/uploads/avatars/1.jpg",
    "status": 1,
    "created_at": "2024-01-10T10:30:00Z",
    "updated_at": "2024-01-10T10:30:00Z"
  }
}

创建用户

接口地址: POST /users

请求头: Authorization: Bearer <token>

请求参数:

{
  "username": "string",    // 用户名,必填
  "email": "string",       // 邮箱,必填
  "password": "string",    // 密码,必填
  "avatar": "string",      // 头像URL可选
  "status": 1              // 状态可选默认1
}

更新用户

接口地址: PUT /users/{id}

请求头: Authorization: Bearer <token>

请求参数:

{
  "username": "string",    // 用户名,可选
  "email": "string",       // 邮箱,可选
  "avatar": "string",      // 头像URL可选
  "status": 1              // 状态,可选
}

删除用户

接口地址: DELETE /users/{id}

请求头: Authorization: Bearer <token>

响应示例:

{
  "code": 200,
  "message": "用户删除成功",
  "data": null
}

上传用户头像

接口地址: POST /users/{id}/avatar

请求头: Authorization: Bearer <token>

请求格式: multipart/form-data

表单字段:

  • file: 图片文件(必填)

响应示例:

{
  "code": 200,
  "message": "头像上传成功",
  "data": {
    "avatar_url": "/uploads/avatars/1_1704875400.jpg"
  }
}

cURL 示例:

curl -X POST "http://localhost:8080/api/v1/users/1/avatar" \
  -H "Authorization: Bearer <your-token>" \
  -F "file=@avatar.jpg"

📸 照片管理接口

获取照片列表

接口地址: GET /photos

查询参数:

  • page: 页码,默认 1
  • limit: 每页数量,默认 10
  • category_id: 分类ID
  • user_id: 用户ID
  • status: 照片状态
  • keyword: 搜索关键词
  • sort: 排序方式,可选值:created_at_desccreated_at_asctitle_asctitle_desc

响应示例:

{
  "code": 200,
  "message": "success",
  "data": {
    "photos": [
      {
        "id": 1,
        "title": "美丽的日落",
        "description": "在海边拍摄的日落景色",
        "file_path": "/uploads/photos/sunset.jpg",
        "thumbnail_path": "/uploads/photos/thumbs/sunset_thumb.jpg",
        "file_size": 2048576,
        "mime_type": "image/jpeg",
        "width": 1920,
        "height": 1080,
        "category_id": 1,
        "category_name": "风景",
        "user_id": 1,
        "username": "johndoe",
        "status": 1,
        "view_count": 150,
        "like_count": 25,
        "created_at": "2024-01-10T10:30:00Z",
        "updated_at": "2024-01-10T10:30:00Z"
      }
    ],
    "total": 100,
    "page": 1,
    "limit": 10,
    "pages": 10
  }
}

获取照片详情

接口地址: GET /photos/{id}

路径参数:

  • id: 照片ID

响应示例:

{
  "code": 200,
  "message": "success",
  "data": {
    "id": 1,
    "title": "美丽的日落",
    "description": "在海边拍摄的日落景色",
    "file_path": "/uploads/photos/sunset.jpg",
    "thumbnail_path": "/uploads/photos/thumbs/sunset_thumb.jpg",
    "file_size": 2048576,
    "mime_type": "image/jpeg",
    "width": 1920,
    "height": 1080,
    "category": {
      "id": 1,
      "name": "风景",
      "description": "自然风光和城市景观"
    },
    "user": {
      "id": 1,
      "username": "johndoe",
      "avatar": "/uploads/avatars/1.jpg"
    },
    "tags": [
      {
        "id": 1,
        "name": "精选",
        "color": "#ff4444"
      }
    ],
    "status": 1,
    "view_count": 150,
    "like_count": 25,
    "created_at": "2024-01-10T10:30:00Z",
    "updated_at": "2024-01-10T10:30:00Z"
  }
}

上传照片

接口地址: POST /photos

请求头: Authorization: Bearer <token>

请求格式: multipart/form-data

表单字段:

  • file: 图片文件(必填)
  • title: 照片标题(必填)
  • description: 照片描述(可选)
  • category_id: 分类ID可选
  • tags: 标签ID列表逗号分隔可选

响应示例:

{
  "code": 200,
  "message": "照片上传成功",
  "data": {
    "id": 1,
    "title": "美丽的日落",
    "description": "在海边拍摄的日落景色",
    "file_path": "/uploads/photos/sunset_1704875400.jpg",
    "thumbnail_path": "/uploads/photos/thumbs/sunset_1704875400_thumb.jpg",
    "file_size": 2048576,
    "mime_type": "image/jpeg",
    "width": 1920,
    "height": 1080,
    "category_id": 1,
    "user_id": 1,
    "status": 1,
    "created_at": "2024-01-10T10:30:00Z"
  }
}

cURL 示例:

curl -X POST "http://localhost:8080/api/v1/photos" \
  -H "Authorization: Bearer <your-token>" \
  -F "file=@sunset.jpg" \
  -F "title=美丽的日落" \
  -F "description=在海边拍摄的日落景色" \
  -F "category_id=1"

更新照片

接口地址: PUT /photos/{id}

请求头: Authorization: Bearer <token>

请求参数:

{
  "title": "string",        // 照片标题,可选
  "description": "string",  // 照片描述,可选
  "category_id": 1,         // 分类ID可选
  "status": 1               // 状态,可选
}

删除照片

接口地址: DELETE /photos/{id}

请求头: Authorization: Bearer <token>

响应示例:

{
  "code": 200,
  "message": "照片删除成功",
  "data": null
}

📂 分类管理接口

获取分类列表

接口地址: GET /categories

查询参数:

  • parent_id: 父分类ID获取子分类
  • is_active: 是否激活,可选值 0、1
  • with_count: 是否包含照片数量统计,默认 false

响应示例:

{
  "code": 200,
  "message": "success",
  "data": [
    {
      "id": 1,
      "name": "风景",
      "description": "自然风光和城市景观",
      "parent_id": null,
      "sort_order": 1,
      "is_active": 1,
      "photo_count": 25,
      "children": [
        {
          "id": 2,
          "name": "海景",
          "description": "海洋和海滩景色",
          "parent_id": 1,
          "sort_order": 1,
          "is_active": 1,
          "photo_count": 10
        }
      ],
      "created_at": "2024-01-10T10:30:00Z",
      "updated_at": "2024-01-10T10:30:00Z"
    }
  ]
}

获取分类详情

接口地址: GET /categories/{id}

路径参数:

  • id: 分类ID

创建分类

接口地址: POST /categories

请求头: Authorization: Bearer <token>

请求参数:

{
  "name": "string",         // 分类名称,必填
  "description": "string",  // 分类描述,可选
  "parent_id": 1,           // 父分类ID可选
  "sort_order": 1,          // 排序序号,可选
  "is_active": 1            // 是否激活,可选
}

更新分类

接口地址: PUT /categories/{id}

请求头: Authorization: Bearer <token>

请求参数:

{
  "name": "string",         // 分类名称,可选
  "description": "string",  // 分类描述,可选
  "parent_id": 1,           // 父分类ID可选
  "sort_order": 1,          // 排序序号,可选
  "is_active": 1            // 是否激活,可选
}

删除分类

接口地址: DELETE /categories/{id}

请求头: Authorization: Bearer <token>

响应示例:

{
  "code": 200,
  "message": "分类删除成功",
  "data": null
}

🏷️ 标签管理接口

获取标签列表

接口地址: GET /tags

查询参数:

  • is_active: 是否激活
  • keyword: 搜索关键词

响应示例:

{
  "code": 200,
  "message": "success",
  "data": [
    {
      "id": 1,
      "name": "精选",
      "color": "#ff4444",
      "description": "精选优质作品",
      "is_active": 1,
      "photo_count": 15,
      "created_at": "2024-01-10T10:30:00Z",
      "updated_at": "2024-01-10T10:30:00Z"
    }
  ]
}

创建标签

接口地址: POST /tags

请求头: Authorization: Bearer <token>

请求参数:

{
  "name": "string",         // 标签名称,必填
  "color": "#ff4444",       // 标签颜色,可选
  "description": "string",  // 标签描述,可选
  "is_active": 1            // 是否激活,可选
}

🏥 健康检查接口

健康检查

接口地址: GET /health

响应示例:

{
  "code": 200,
  "message": "success",
  "data": {
    "status": "ok",
    "timestamp": "2024-01-10T10:30:00Z",
    "version": "v1.0.0",
    "uptime": "2h30m15s",
    "database": "connected",
    "redis": "connected"
  }
}

📊 统计接口

获取仪表盘统计

接口地址: GET /dashboard/stats

请求头: Authorization: Bearer <token>

响应示例:

{
  "code": 200,
  "message": "success",
  "data": {
    "users": {
      "total": 150,
      "active": 142,
      "new_today": 5
    },
    "photos": {
      "total": 2500,
      "published": 2350,
      "new_today": 25,
      "total_views": 150000,
      "total_likes": 8500
    },
    "categories": {
      "total": 12,
      "active": 10
    },
    "tags": {
      "total": 25,
      "active": 22
    },
    "storage": {
      "used": "15.5GB",
      "total": "100GB",
      "usage_percent": 15.5
    }
  }
}

🔧 文件服务接口

静态文件访问

接口地址: GET /uploads/{path}

路径参数:

  • path: 文件相对路径

示例:

  • 照片原图: GET /uploads/photos/sunset_1704875400.jpg
  • 缩略图: GET /uploads/photos/thumbs/sunset_1704875400_thumb.jpg
  • 用户头像: GET /uploads/avatars/1_1704875400.jpg

📝 开发指南

环境配置

  1. 开发环境:

    # 设置环境变量
    export ENV=development
    export DATABASE_HOST=localhost
    export DATABASE_PORT=5432
    export JWT_SECRET=your-jwt-secret
    
    # 启动服务
    go run cmd/api/main.go -f etc/photography-api.yaml
    
  2. 生产环境:

    # 使用 Docker Compose
    docker-compose -f configs/docker/docker-compose.prod.yml up -d
    

认证流程

  1. 用户注册或登录获取 JWT Token
  2. 在请求头中添加 Authorization: Bearer <token>
  3. 服务器验证 Token 并提取用户信息
  4. 权限检查通过后执行业务逻辑

错误处理

API 遵循统一的错误处理机制:

{
  "code": 400,
  "message": "参数验证失败: 用户名不能为空",
  "data": null
}

常见错误码:

  • 401: 未登录或 Token 无效
  • 403: 权限不足
  • 400: 参数错误
  • 404: 资源不存在
  • 500: 服务器错误

性能优化

  1. 分页查询: 大数据量接口支持分页,减少单次传输数据量
  2. 字段过滤: 支持 fields 参数指定返回字段
  3. 缓存机制: 热点数据使用 Redis 缓存
  4. 数据库优化: 合理使用索引避免N+1查询

安全考虑

  1. 输入验证: 所有用户输入都进行严格验证
  2. SQL注入防护: 使用参数化查询
  3. 文件上传安全: 文件类型和大小限制
  4. Rate Limiting: 接口频率限制
  5. CORS配置: 跨域请求控制

📚 SDK 和工具

JavaScript/TypeScript SDK

import { PhotographyAPI } from 'photography-api-sdk';

const api = new PhotographyAPI({
  baseURL: 'https://api.photography.iriver.top/api/v1',
  token: 'your-jwt-token'
});

// 获取照片列表
const photos = await api.photos.list({
  page: 1,
  limit: 10,
  category_id: 1
});

// 上传照片
const photo = await api.photos.upload({
  file: fileBlob,
  title: '美丽的日落',
  description: '在海边拍摄的日落景色',
  category_id: 1
});

Postman Collection

项目提供完整的 Postman Collection包含所有接口的示例请求

# 导入 Postman Collection
curl -o photography-api.postman_collection.json \
  https://raw.githubusercontent.com/photography/api-docs/main/postman/collection.json

OpenAPI 规范

API 提供标准的 OpenAPI 3.0 规范文档:

  • Swagger UI: https://api.photography.iriver.top/swagger
  • OpenAPI JSON: https://api.photography.iriver.top/api/openapi.json

🚀 部署说明

Docker 部署

# 拉取镜像
docker pull photography/api:latest

# 运行容器
docker run -d \
  --name photography-api \
  -p 8080:8080 \
  -e DATABASE_HOST=your-db-host \
  -e DATABASE_PASSWORD=your-db-password \
  -e JWT_SECRET=your-jwt-secret \
  photography/api:latest

Kubernetes 部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: photography-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: photography-api
  template:
    metadata:
      labels:
        app: photography-api
    spec:
      containers:
      - name: api
        image: photography/api:latest
        ports:
        - containerPort: 8080
        env:
        - name: DATABASE_HOST
          value: "postgres-service"
        - name: JWT_SECRET
          valueFrom:
            secretKeyRef:
              name: api-secrets
              key: jwt-secret

📞 支持


最后更新: 2024-01-10