## 🧪 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文档,便于前后端协作 - 性能优化和监控配置,确保生产稳定性
17 KiB
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: 页码,默认 1limit: 每页数量,默认 10,最大 100status: 用户状态,可选值 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: 页码,默认 1limit: 每页数量,默认 10category_id: 分类IDuser_id: 用户IDstatus: 照片状态keyword: 搜索关键词sort: 排序方式,可选值:created_at_desc、created_at_asc、title_asc、title_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、1with_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
📝 开发指南
环境配置
-
开发环境:
# 设置环境变量 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 -
生产环境:
# 使用 Docker Compose docker-compose -f configs/docker/docker-compose.prod.yml up -d
认证流程
- 用户注册或登录获取 JWT Token
- 在请求头中添加
Authorization: Bearer <token> - 服务器验证 Token 并提取用户信息
- 权限检查通过后执行业务逻辑
错误处理
API 遵循统一的错误处理机制:
{
"code": 400,
"message": "参数验证失败: 用户名不能为空",
"data": null
}
常见错误码:
401: 未登录或 Token 无效403: 权限不足400: 参数错误404: 资源不存在500: 服务器错误
性能优化
- 分页查询: 大数据量接口支持分页,减少单次传输数据量
- 字段过滤: 支持
fields参数指定返回字段 - 缓存机制: 热点数据使用 Redis 缓存
- 数据库优化: 合理使用索引,避免N+1查询
安全考虑
- 输入验证: 所有用户输入都进行严格验证
- SQL注入防护: 使用参数化查询
- 文件上传安全: 文件类型和大小限制
- Rate Limiting: 接口频率限制
- 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
📞 支持
- 技术文档: https://docs.photography.iriver.top
- GitHub Issues: https://github.com/photography/api/issues
- 邮箱支持: api-support@photography.com
最后更新: 2024-01-10