## 主要变更 - 创建版本化文档目录结构 (v1/, v2/) - 移动核心设计文档到对应版本目录 - 更新文档总览和版本说明 - 保留原有目录结构的兼容性 ## 新增文档 - docs/v1/README.md - v1.0版本开发指南 - docs/v2/README.md - v2.0版本规划文档 - docs/v1/admin/管理后台开发文档.md - docs/v1/backend/Golang项目架构文档.md - docs/v1/database/数据库设计文档.md - docs/v1/api/API接口设计文档.md ## 文档结构优化 - 清晰的版本划分,便于开发者快速定位 - 完整的开发进度跟踪 - 详细的技术栈说明和架构设计 - 未来版本功能规划和技术演进路径 ## 开发者体验提升 - 角色导向的文档导航 - 快速开始指南 - 详细的API和数据库设计文档 - 版本化管理便于迭代开发
1569 lines
32 KiB
Markdown
1569 lines
32 KiB
Markdown
# 摄影作品集网站 - API接口设计文档
|
||
|
||
## 1. API 概述
|
||
|
||
### 1.1 设计原则
|
||
- **RESTful 设计**: 遵循 REST 架构风格
|
||
- **统一响应格式**: 标准化的 JSON 响应结构
|
||
- **版本控制**: API 版本化管理
|
||
- **安全认证**: JWT 令牌认证机制
|
||
- **错误处理**: 详细的错误码和错误信息
|
||
- **性能优化**: 支持分页、筛选、排序
|
||
|
||
### 1.2 基础信息
|
||
```yaml
|
||
Base URL: https://api.photography.iriver.top
|
||
API Version: v1
|
||
Content-Type: application/json
|
||
Authentication: Bearer Token (JWT)
|
||
```
|
||
|
||
### 1.3 通用响应格式
|
||
|
||
#### 1.3.1 成功响应
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"message": "Success",
|
||
"data": {
|
||
// 具体数据内容
|
||
},
|
||
"meta": {
|
||
"timestamp": "2024-01-15T10:30:00Z",
|
||
"request_id": "req_123456789"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 1.3.2 分页响应
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"message": "Success",
|
||
"data": [
|
||
// 数据列表
|
||
],
|
||
"pagination": {
|
||
"page": 1,
|
||
"limit": 20,
|
||
"total": 150,
|
||
"total_pages": 8,
|
||
"has_next": true,
|
||
"has_prev": false
|
||
},
|
||
"meta": {
|
||
"timestamp": "2024-01-15T10:30:00Z",
|
||
"request_id": "req_123456789"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 1.3.3 错误响应
|
||
```json
|
||
{
|
||
"success": false,
|
||
"code": 400,
|
||
"message": "Bad Request",
|
||
"error": {
|
||
"type": "VALIDATION_ERROR",
|
||
"details": [
|
||
{
|
||
"field": "title",
|
||
"message": "Title is required"
|
||
}
|
||
]
|
||
},
|
||
"meta": {
|
||
"timestamp": "2024-01-15T10:30:00Z",
|
||
"request_id": "req_123456789"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 1.4 HTTP 状态码规范
|
||
|
||
| 状态码 | 说明 | 使用场景 |
|
||
|--------|------|----------|
|
||
| 200 | OK | 请求成功 |
|
||
| 201 | Created | 资源创建成功 |
|
||
| 204 | No Content | 删除成功 |
|
||
| 400 | Bad Request | 请求参数错误 |
|
||
| 401 | Unauthorized | 未认证 |
|
||
| 403 | Forbidden | 权限不足 |
|
||
| 404 | Not Found | 资源不存在 |
|
||
| 409 | Conflict | 资源冲突 |
|
||
| 422 | Unprocessable Entity | 数据验证失败 |
|
||
| 429 | Too Many Requests | 请求过于频繁 |
|
||
| 500 | Internal Server Error | 服务器内部错误 |
|
||
|
||
## 2. 认证与授权
|
||
|
||
### 2.1 认证机制
|
||
|
||
#### 2.1.1 登录认证
|
||
```http
|
||
POST /v1/auth/login
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"username": "admin",
|
||
"password": "password123"
|
||
}
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"message": "Login successful",
|
||
"data": {
|
||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"token_type": "Bearer",
|
||
"expires_in": 86400,
|
||
"user": {
|
||
"id": 1,
|
||
"username": "admin",
|
||
"email": "admin@example.com",
|
||
"role": "admin",
|
||
"display_name": "管理员",
|
||
"avatar_url": "https://example.com/avatar.jpg"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2.1.2 令牌刷新
|
||
```http
|
||
POST /v1/auth/refresh
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
}
|
||
```
|
||
|
||
#### 2.1.3 登出
|
||
```http
|
||
POST /v1/auth/logout
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
#### 2.1.4 用户信息
|
||
```http
|
||
GET /v1/auth/profile
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
### 2.2 权限控制
|
||
|
||
#### 2.2.1 权限级别
|
||
```json
|
||
{
|
||
"roles": {
|
||
"super_admin": {
|
||
"name": "超级管理员",
|
||
"permissions": ["*"]
|
||
},
|
||
"admin": {
|
||
"name": "管理员",
|
||
"permissions": [
|
||
"photo.*",
|
||
"category.*",
|
||
"tag.*",
|
||
"user.read",
|
||
"user.update",
|
||
"settings.*"
|
||
]
|
||
},
|
||
"editor": {
|
||
"name": "编辑者",
|
||
"permissions": [
|
||
"photo.read",
|
||
"photo.create",
|
||
"photo.update",
|
||
"category.read",
|
||
"tag.read",
|
||
"tag.create"
|
||
]
|
||
},
|
||
"user": {
|
||
"name": "普通用户",
|
||
"permissions": [
|
||
"photo.read",
|
||
"category.read",
|
||
"tag.read"
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 3. 照片管理 API
|
||
|
||
### 3.1 照片列表
|
||
|
||
#### 3.1.1 获取照片列表
|
||
```http
|
||
GET /v1/photos?page=1&limit=20&status=published&category=1&tag=nature&search=sunset&sort_by=created_at&sort_order=desc
|
||
```
|
||
|
||
**查询参数:**
|
||
| 参数 | 类型 | 必填 | 说明 | 示例 |
|
||
|------|------|------|------|------|
|
||
| page | integer | 否 | 页码,默认1 | 1 |
|
||
| limit | integer | 否 | 每页数量,默认20 | 20 |
|
||
| status | string | 否 | 状态筛选 | published, draft, archived |
|
||
| category | integer | 否 | 分类ID | 1 |
|
||
| tag | string | 否 | 标签名称 | nature |
|
||
| search | string | 否 | 搜索关键词 | sunset |
|
||
| sort_by | string | 否 | 排序字段 | created_at, taken_at, title |
|
||
| sort_order | string | 否 | 排序方向 | asc, desc |
|
||
| year | integer | 否 | 年份筛选 | 2024 |
|
||
| month | integer | 否 | 月份筛选 | 1 |
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"title": "城市夜景",
|
||
"description": "繁华都市的夜晚景色",
|
||
"slug": "city-night-view-001",
|
||
"status": "published",
|
||
"visibility": "public",
|
||
"taken_at": "2024-01-15T18:30:00Z",
|
||
"created_at": "2024-01-15T20:00:00Z",
|
||
"updated_at": "2024-01-15T20:00:00Z",
|
||
"view_count": 156,
|
||
"like_count": 23,
|
||
"formats": {
|
||
"thumb_small": "https://cdn.example.com/photos/1/thumb_small.jpg",
|
||
"thumb_medium": "https://cdn.example.com/photos/1/thumb_medium.jpg",
|
||
"thumb_large": "https://cdn.example.com/photos/1/thumb_large.jpg",
|
||
"display": "https://cdn.example.com/photos/1/display.jpg",
|
||
"webp": "https://cdn.example.com/photos/1/display.webp"
|
||
},
|
||
"exif": {
|
||
"camera": "Canon EOS R5",
|
||
"lens": "RF 24-70mm f/2.8L IS USM",
|
||
"iso": 800,
|
||
"aperture": "f/2.8",
|
||
"shutter_speed": "1/125",
|
||
"focal_length": "50mm"
|
||
},
|
||
"location": {
|
||
"name": "上海外滩",
|
||
"latitude": 31.23037,
|
||
"longitude": 121.47370,
|
||
"country": "China",
|
||
"city": "Shanghai"
|
||
},
|
||
"categories": [
|
||
{
|
||
"id": 1,
|
||
"name": "城市风光",
|
||
"slug": "cityscape",
|
||
"color": "#3498db"
|
||
}
|
||
],
|
||
"tags": [
|
||
{
|
||
"id": 1,
|
||
"name": "夜景",
|
||
"slug": "night-view",
|
||
"color": "#2c3e50"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"name": "城市",
|
||
"slug": "city",
|
||
"color": "#e74c3c"
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"pagination": {
|
||
"page": 1,
|
||
"limit": 20,
|
||
"total": 150,
|
||
"total_pages": 8,
|
||
"has_next": true,
|
||
"has_prev": false
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.2 照片详情
|
||
|
||
#### 3.2.1 获取照片详情
|
||
```http
|
||
GET /v1/photos/{id}
|
||
```
|
||
|
||
**路径参数:**
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| id | integer | 是 | 照片ID |
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": {
|
||
"id": 1,
|
||
"title": "城市夜景",
|
||
"description": "繁华都市的夜晚景色,灯火通明的建筑群构成了美丽的天际线...",
|
||
"slug": "city-night-view-001",
|
||
"status": "published",
|
||
"visibility": "public",
|
||
"sort_order": 0,
|
||
"taken_at": "2024-01-15T18:30:00Z",
|
||
"created_at": "2024-01-15T20:00:00Z",
|
||
"updated_at": "2024-01-15T20:00:00Z",
|
||
"view_count": 156,
|
||
"like_count": 23,
|
||
"download_count": 5,
|
||
"file_info": {
|
||
"original_filename": "DSC_0001.jpg",
|
||
"file_size": 2048576,
|
||
"mime_type": "image/jpeg"
|
||
},
|
||
"formats": {
|
||
"original": "https://cdn.example.com/photos/1/original.jpg",
|
||
"jpg": "https://cdn.example.com/photos/1/display.jpg",
|
||
"webp": "https://cdn.example.com/photos/1/display.webp",
|
||
"thumb_small": "https://cdn.example.com/photos/1/thumb_small.jpg",
|
||
"thumb_medium": "https://cdn.example.com/photos/1/thumb_medium.jpg",
|
||
"thumb_large": "https://cdn.example.com/photos/1/thumb_large.jpg"
|
||
},
|
||
"exif": {
|
||
"camera": "Canon EOS R5",
|
||
"lens": "RF 24-70mm f/2.8L IS USM",
|
||
"iso": 800,
|
||
"aperture": "f/2.8",
|
||
"shutter_speed": "1/125",
|
||
"focal_length": "50mm"
|
||
},
|
||
"location": {
|
||
"name": "上海外滩",
|
||
"latitude": 31.23037,
|
||
"longitude": 121.47370,
|
||
"country": "China",
|
||
"city": "Shanghai"
|
||
},
|
||
"categories": [
|
||
{
|
||
"id": 1,
|
||
"name": "城市风光",
|
||
"slug": "cityscape",
|
||
"description": "城市景观摄影作品",
|
||
"color": "#3498db",
|
||
"is_primary": true
|
||
}
|
||
],
|
||
"tags": [
|
||
{
|
||
"id": 1,
|
||
"name": "夜景",
|
||
"slug": "night-view",
|
||
"color": "#2c3e50",
|
||
"confidence": 1.0,
|
||
"source": "manual"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"name": "城市",
|
||
"slug": "city",
|
||
"color": "#e74c3c",
|
||
"confidence": 0.95,
|
||
"source": "ai"
|
||
}
|
||
],
|
||
"metadata": {
|
||
"weather": "clear",
|
||
"temperature": "15°C",
|
||
"processing_notes": "调整了曝光和对比度"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.3 照片操作
|
||
|
||
#### 3.3.1 创建照片 (用于上传后的元数据创建)
|
||
```http
|
||
POST /v1/photos
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"title": "城市夜景",
|
||
"description": "繁华都市的夜晚景色",
|
||
"file_id": "upload_123456789",
|
||
"status": "published",
|
||
"visibility": "public",
|
||
"taken_at": "2024-01-15T18:30:00Z",
|
||
"location": {
|
||
"name": "上海外滩",
|
||
"latitude": 31.23037,
|
||
"longitude": 121.47370
|
||
},
|
||
"categories": [1, 2],
|
||
"tags": ["夜景", "城市", "建筑"],
|
||
"metadata": {
|
||
"weather": "clear",
|
||
"temperature": "15°C"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3.3.2 更新照片信息
|
||
```http
|
||
PUT /v1/photos/{id}
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"title": "上海外滩夜景",
|
||
"description": "更新后的描述",
|
||
"status": "published",
|
||
"categories": [1, 3],
|
||
"tags": ["夜景", "城市", "外滩"]
|
||
}
|
||
```
|
||
|
||
#### 3.3.3 删除照片
|
||
```http
|
||
DELETE /v1/photos/{id}
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
#### 3.3.4 批量操作
|
||
```http
|
||
POST /v1/photos/batch
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"photo_ids": [1, 2, 3, 4, 5],
|
||
"action": "update_status",
|
||
"data": {
|
||
"status": "published"
|
||
}
|
||
}
|
||
```
|
||
|
||
**支持的批量操作:**
|
||
- `update_status`: 批量更新状态
|
||
- `add_tags`: 批量添加标签
|
||
- `remove_tags`: 批量移除标签
|
||
- `add_categories`: 批量添加分类
|
||
- `remove_categories`: 批量移除分类
|
||
- `delete`: 批量删除
|
||
|
||
### 3.4 照片搜索
|
||
|
||
#### 3.4.1 全文搜索
|
||
```http
|
||
GET /v1/photos/search?q=夜景&category=1&tags=城市,建筑&location=上海&date_from=2024-01-01&date_to=2024-12-31
|
||
```
|
||
|
||
**查询参数:**
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| q | string | 是 | 搜索关键词 |
|
||
| category | integer | 否 | 分类ID |
|
||
| tags | string | 否 | 标签名称,逗号分隔 |
|
||
| location | string | 否 | 地点名称 |
|
||
| date_from | string | 否 | 开始日期 (YYYY-MM-DD) |
|
||
| date_to | string | 否 | 结束日期 (YYYY-MM-DD) |
|
||
| camera | string | 否 | 相机型号 |
|
||
| lens | string | 否 | 镜头型号 |
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": {
|
||
"photos": [
|
||
{
|
||
"id": 1,
|
||
"title": "城市夜景",
|
||
"score": 0.95,
|
||
"highlight": {
|
||
"title": "<mark>夜景</mark>",
|
||
"description": "繁华都市的<mark>夜晚</mark>景色"
|
||
}
|
||
}
|
||
],
|
||
"facets": {
|
||
"categories": [
|
||
{"name": "城市风光", "count": 15},
|
||
{"name": "建筑摄影", "count": 8}
|
||
],
|
||
"tags": [
|
||
{"name": "夜景", "count": 12},
|
||
{"name": "城市", "count": 20}
|
||
],
|
||
"years": [
|
||
{"year": 2024, "count": 25},
|
||
{"year": 2023, "count": 18}
|
||
]
|
||
}
|
||
},
|
||
"pagination": {
|
||
"page": 1,
|
||
"limit": 20,
|
||
"total": 25
|
||
}
|
||
}
|
||
```
|
||
|
||
## 4. 文件上传 API
|
||
|
||
### 4.1 文件上传
|
||
|
||
#### 4.1.1 单文件上传
|
||
```http
|
||
POST /v1/upload/single
|
||
Authorization: Bearer {token}
|
||
Content-Type: multipart/form-data
|
||
|
||
file: (binary data)
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 201,
|
||
"data": {
|
||
"file_id": "upload_123456789",
|
||
"original_filename": "DSC_0001.jpg",
|
||
"file_size": 2048576,
|
||
"mime_type": "image/jpeg",
|
||
"upload_url": "https://temp.example.com/upload_123456789.jpg",
|
||
"status": "uploaded",
|
||
"exif_extracted": true,
|
||
"processing_status": "pending"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.1.2 多文件上传
|
||
```http
|
||
POST /v1/upload/multiple
|
||
Authorization: Bearer {token}
|
||
Content-Type: multipart/form-data
|
||
|
||
files[]: (binary data)
|
||
files[]: (binary data)
|
||
...
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 201,
|
||
"data": {
|
||
"uploaded": [
|
||
{
|
||
"file_id": "upload_123456789",
|
||
"original_filename": "DSC_0001.jpg",
|
||
"file_size": 2048576,
|
||
"status": "uploaded"
|
||
}
|
||
],
|
||
"failed": [
|
||
{
|
||
"filename": "invalid_file.txt",
|
||
"error": "Invalid file type"
|
||
}
|
||
],
|
||
"summary": {
|
||
"total": 5,
|
||
"success": 4,
|
||
"failed": 1
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.1.3 分块上传
|
||
```http
|
||
POST /v1/upload/chunked/init
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"filename": "large_photo.raw",
|
||
"file_size": 52428800,
|
||
"mime_type": "image/raw",
|
||
"chunk_size": 1048576
|
||
}
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 201,
|
||
"data": {
|
||
"upload_id": "chunked_123456789",
|
||
"chunk_size": 1048576,
|
||
"total_chunks": 50,
|
||
"upload_urls": [
|
||
"https://temp.example.com/chunked_123456789/chunk_0",
|
||
"https://temp.example.com/chunked_123456789/chunk_1"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.1.4 上传状态查询
|
||
```http
|
||
GET /v1/upload/status/{file_id}
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": {
|
||
"file_id": "upload_123456789",
|
||
"status": "processing",
|
||
"progress": 75,
|
||
"current_step": "generating_thumbnails",
|
||
"steps": [
|
||
{"name": "uploaded", "status": "completed"},
|
||
{"name": "exif_extraction", "status": "completed"},
|
||
{"name": "generating_thumbnails", "status": "processing"},
|
||
{"name": "optimization", "status": "pending"}
|
||
],
|
||
"estimated_time_remaining": 30
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.2 文件处理
|
||
|
||
#### 4.2.1 重新处理文件
|
||
```http
|
||
POST /v1/upload/{file_id}/reprocess
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"formats": ["thumb_small", "thumb_medium", "webp"],
|
||
"force": true
|
||
}
|
||
```
|
||
|
||
#### 4.2.2 删除上传文件
|
||
```http
|
||
DELETE /v1/upload/{file_id}
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
## 5. 分类管理 API
|
||
|
||
### 5.1 分类操作
|
||
|
||
#### 5.1.1 获取分类列表
|
||
```http
|
||
GET /v1/categories?include_stats=true&include_tree=true
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": {
|
||
"categories": [
|
||
{
|
||
"id": 1,
|
||
"name": "城市风光",
|
||
"slug": "cityscape",
|
||
"description": "城市景观摄影作品",
|
||
"parent_id": null,
|
||
"level": 0,
|
||
"path": "1",
|
||
"cover_photo": {
|
||
"id": 15,
|
||
"title": "都市夜景",
|
||
"thumb_url": "https://cdn.example.com/photos/15/thumb_medium.jpg"
|
||
},
|
||
"color": "#3498db",
|
||
"icon": "building",
|
||
"sort_order": 1,
|
||
"is_active": true,
|
||
"is_featured": true,
|
||
"photo_count": 45,
|
||
"direct_photo_count": 30,
|
||
"created_at": "2024-01-01T00:00:00Z",
|
||
"updated_at": "2024-01-15T10:30:00Z"
|
||
}
|
||
],
|
||
"tree": [
|
||
{
|
||
"id": 1,
|
||
"name": "城市风光",
|
||
"slug": "cityscape",
|
||
"photo_count": 45,
|
||
"children": [
|
||
{
|
||
"id": 2,
|
||
"name": "夜景摄影",
|
||
"slug": "night-photography",
|
||
"photo_count": 15,
|
||
"children": []
|
||
},
|
||
{
|
||
"id": 3,
|
||
"name": "建筑摄影",
|
||
"slug": "architecture",
|
||
"photo_count": 30,
|
||
"children": []
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"stats": {
|
||
"total_categories": 12,
|
||
"max_level": 3,
|
||
"featured_count": 5
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 5.1.2 获取分类详情
|
||
```http
|
||
GET /v1/categories/{id}
|
||
```
|
||
|
||
#### 5.1.3 创建分类
|
||
```http
|
||
POST /v1/categories
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "自然风景",
|
||
"slug": "nature-landscape",
|
||
"description": "自然风景摄影作品",
|
||
"parent_id": null,
|
||
"color": "#27ae60",
|
||
"icon": "tree",
|
||
"sort_order": 2,
|
||
"is_featured": true,
|
||
"seo_title": "自然风景摄影作品集",
|
||
"seo_description": "欣赏美丽的自然风景摄影作品"
|
||
}
|
||
```
|
||
|
||
#### 5.1.4 更新分类
|
||
```http
|
||
PUT /v1/categories/{id}
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "自然风光",
|
||
"description": "更新后的描述",
|
||
"color": "#2ecc71"
|
||
}
|
||
```
|
||
|
||
#### 5.1.5 删除分类
|
||
```http
|
||
DELETE /v1/categories/{id}
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
#### 5.1.6 设置分类封面
|
||
```http
|
||
PUT /v1/categories/{id}/cover
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"photo_id": 15
|
||
}
|
||
```
|
||
|
||
### 5.2 分类照片管理
|
||
|
||
#### 5.2.1 获取分类下的照片
|
||
```http
|
||
GET /v1/categories/{id}/photos?page=1&limit=20&sort_by=created_at&sort_order=desc
|
||
```
|
||
|
||
#### 5.2.2 添加照片到分类
|
||
```http
|
||
POST /v1/categories/{id}/photos
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"photo_ids": [1, 2, 3],
|
||
"is_primary": true
|
||
}
|
||
```
|
||
|
||
#### 5.2.3 从分类移除照片
|
||
```http
|
||
DELETE /v1/categories/{id}/photos
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"photo_ids": [1, 2, 3]
|
||
}
|
||
```
|
||
|
||
## 6. 标签管理 API
|
||
|
||
### 6.1 标签操作
|
||
|
||
#### 6.1.1 获取标签列表
|
||
```http
|
||
GET /v1/tags?group=all&sort_by=usage_count&sort_order=desc&limit=50
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"name": "夜景",
|
||
"slug": "night-view",
|
||
"description": "夜晚拍摄的景色",
|
||
"color": "#2c3e50",
|
||
"icon": "moon",
|
||
"tag_group": "style",
|
||
"usage_count": 45,
|
||
"trend_score": 8.5,
|
||
"is_active": true,
|
||
"is_featured": true,
|
||
"created_at": "2024-01-01T00:00:00Z",
|
||
"last_used_at": "2024-01-15T10:30:00Z"
|
||
}
|
||
],
|
||
"groups": {
|
||
"style": {"name": "摄影风格", "count": 12},
|
||
"subject": {"name": "拍摄主题", "count": 18},
|
||
"technique": {"name": "拍摄技法", "count": 8},
|
||
"location": {"name": "地理位置", "count": 25}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 6.1.2 标签搜索建议
|
||
```http
|
||
GET /v1/tags/suggestions?q=夜&limit=10
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"name": "夜景",
|
||
"slug": "night-view",
|
||
"usage_count": 45,
|
||
"match_score": 0.95
|
||
},
|
||
{
|
||
"id": 15,
|
||
"name": "夜市",
|
||
"slug": "night-market",
|
||
"usage_count": 12,
|
||
"match_score": 0.8
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 6.1.3 创建标签
|
||
```http
|
||
POST /v1/tags
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "极光",
|
||
"slug": "aurora",
|
||
"description": "极光摄影作品",
|
||
"color": "#9b59b6",
|
||
"tag_group": "subject",
|
||
"is_featured": true
|
||
}
|
||
```
|
||
|
||
#### 6.1.4 更新标签
|
||
```http
|
||
PUT /v1/tags/{id}
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "北极光",
|
||
"description": "更新后的描述",
|
||
"color": "#8e44ad"
|
||
}
|
||
```
|
||
|
||
#### 6.1.5 删除标签
|
||
```http
|
||
DELETE /v1/tags/{id}
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
### 6.2 标签统计
|
||
|
||
#### 6.2.1 标签云数据
|
||
```http
|
||
GET /v1/tags/cloud?min_usage=5&max_tags=50
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"name": "夜景",
|
||
"usage_count": 45,
|
||
"relative_size": 100,
|
||
"color": "#2c3e50"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"name": "城市",
|
||
"usage_count": 38,
|
||
"relative_size": 84,
|
||
"color": "#e74c3c"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 6.2.2 趋势标签
|
||
```http
|
||
GET /v1/tags/trending?period=30d&limit=10
|
||
```
|
||
|
||
## 7. 时间线 API
|
||
|
||
### 7.1 时间线数据
|
||
|
||
#### 7.1.1 获取时间线
|
||
```http
|
||
GET /v1/timeline?year=2024&include_photos=true&photos_limit=5
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": {
|
||
"years": [
|
||
{
|
||
"year": 2024,
|
||
"photo_count": 156,
|
||
"months": [
|
||
{
|
||
"month": 1,
|
||
"month_name": "一月",
|
||
"photo_count": 25,
|
||
"photos": [
|
||
{
|
||
"id": 1,
|
||
"title": "城市夜景",
|
||
"thumb_url": "https://cdn.example.com/photos/1/thumb_medium.jpg",
|
||
"taken_at": "2024-01-15T18:30:00Z"
|
||
}
|
||
],
|
||
"events": [
|
||
{
|
||
"id": 1,
|
||
"title": "首次夜景拍摄",
|
||
"description": "第一次尝试城市夜景摄影",
|
||
"date": "2024-01-15",
|
||
"type": "milestone"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"stats": {
|
||
"total_photos": 456,
|
||
"year_range": [2020, 2024],
|
||
"most_active_month": {
|
||
"year": 2024,
|
||
"month": 3,
|
||
"count": 45
|
||
},
|
||
"photos_by_year": [
|
||
{"year": 2024, "count": 156},
|
||
{"year": 2023, "count": 189},
|
||
{"year": 2022, "count": 111}
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 7.1.2 获取指定月份详情
|
||
```http
|
||
GET /v1/timeline/{year}/{month}?include_photos=true
|
||
```
|
||
|
||
### 7.2 时间线事件
|
||
|
||
#### 7.2.1 创建事件
|
||
```http
|
||
POST /v1/timeline/events
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"title": "获得摄影比赛奖项",
|
||
"description": "在城市摄影大赛中获得金奖",
|
||
"date": "2024-03-15",
|
||
"type": "achievement",
|
||
"related_photos": [15, 23, 31]
|
||
}
|
||
```
|
||
|
||
#### 7.2.2 更新事件
|
||
```http
|
||
PUT /v1/timeline/events/{id}
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"title": "更新后的标题",
|
||
"description": "更新后的描述"
|
||
}
|
||
```
|
||
|
||
#### 7.2.3 删除事件
|
||
```http
|
||
DELETE /v1/timeline/events/{id}
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
## 8. 系统设置 API
|
||
|
||
### 8.1 设置管理
|
||
|
||
#### 8.1.1 获取系统设置
|
||
```http
|
||
GET /v1/settings?category=all&include_public=true
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": {
|
||
"general": {
|
||
"site_title": "摄影作品集",
|
||
"site_description": "专业摄影师作品展示平台",
|
||
"site_keywords": "摄影,作品集,艺术,创作",
|
||
"site_author": "摄影师姓名",
|
||
"site_email": "contact@example.com"
|
||
},
|
||
"upload": {
|
||
"max_file_size": 52428800,
|
||
"allowed_types": ["image/jpeg", "image/png", "image/raw"],
|
||
"max_files_per_batch": 50,
|
||
"auto_publish": false,
|
||
"generate_thumbnails": true
|
||
},
|
||
"image": {
|
||
"quality_jpg": 85,
|
||
"quality_webp": 80,
|
||
"max_width": 1920,
|
||
"max_height": 1080,
|
||
"watermark_enabled": false
|
||
},
|
||
"display": {
|
||
"photos_per_page": 20,
|
||
"thumbnail_size": 300,
|
||
"theme_primary_color": "#d4af37",
|
||
"theme_secondary_color": "#2d2d2d",
|
||
"enable_dark_mode": true,
|
||
"enable_animations": true
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 8.1.2 更新系统设置
|
||
```http
|
||
PUT /v1/settings
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"site_title": "我的摄影作品集",
|
||
"upload_max_file_size": 104857600,
|
||
"display_photos_per_page": 24
|
||
}
|
||
```
|
||
|
||
#### 8.1.3 重置设置
|
||
```http
|
||
POST /v1/settings/reset
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"categories": ["upload", "image"],
|
||
"confirm": true
|
||
}
|
||
```
|
||
|
||
### 8.2 缓存管理
|
||
|
||
#### 8.2.1 清理缓存
|
||
```http
|
||
POST /v1/settings/cache/clear
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"types": ["photos", "categories", "tags", "settings"],
|
||
"confirm": true
|
||
}
|
||
```
|
||
|
||
#### 8.2.2 预热缓存
|
||
```http
|
||
POST /v1/settings/cache/warm
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"types": ["popular_photos", "category_tree", "tag_cloud"]
|
||
}
|
||
```
|
||
|
||
#### 8.2.3 缓存统计
|
||
```http
|
||
GET /v1/settings/cache/stats
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": {
|
||
"redis": {
|
||
"connected": true,
|
||
"used_memory": "15.2MB",
|
||
"total_keys": 1247,
|
||
"hit_rate": 0.89
|
||
},
|
||
"categories": {
|
||
"photos": {"keys": 456, "hit_rate": 0.92},
|
||
"categories": {"keys": 12, "hit_rate": 0.95},
|
||
"tags": {"keys": 89, "hit_rate": 0.87},
|
||
"settings": {"keys": 1, "hit_rate": 0.99}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 9. 统计分析 API
|
||
|
||
### 9.1 仪表板统计
|
||
|
||
#### 9.1.1 仪表板数据
|
||
```http
|
||
GET /v1/dashboard/stats?period=30d
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"code": 200,
|
||
"data": {
|
||
"summary": {
|
||
"total_photos": 456,
|
||
"total_categories": 12,
|
||
"total_tags": 89,
|
||
"total_views": 15420,
|
||
"storage_used": 2684354560,
|
||
"storage_limit": 10737418240
|
||
},
|
||
"recent": {
|
||
"new_photos": 15,
|
||
"new_views": 234,
|
||
"new_likes": 67,
|
||
"period": "7d"
|
||
},
|
||
"trends": {
|
||
"uploads": [
|
||
{"date": "2024-01-01", "count": 5},
|
||
{"date": "2024-01-02", "count": 8},
|
||
{"date": "2024-01-03", "count": 3}
|
||
],
|
||
"views": [
|
||
{"date": "2024-01-01", "count": 156},
|
||
{"date": "2024-01-02", "count": 234},
|
||
{"date": "2024-01-03", "count": 189}
|
||
]
|
||
},
|
||
"popular": {
|
||
"categories": [
|
||
{"name": "城市风光", "count": 45, "percentage": 28.5},
|
||
{"name": "自然风景", "count": 38, "percentage": 24.1}
|
||
],
|
||
"tags": [
|
||
{"name": "夜景", "count": 45},
|
||
{"name": "城市", "count": 38}
|
||
],
|
||
"photos": [
|
||
{
|
||
"id": 15,
|
||
"title": "都市夜景",
|
||
"view_count": 1247,
|
||
"like_count": 89
|
||
}
|
||
]
|
||
},
|
||
"system_status": {
|
||
"database": "healthy",
|
||
"redis": "healthy",
|
||
"storage": "healthy",
|
||
"queue": "healthy"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 9.2 详细统计
|
||
|
||
#### 9.2.1 照片统计
|
||
```http
|
||
GET /v1/stats/photos?group_by=month&year=2024
|
||
```
|
||
|
||
#### 9.2.2 访问统计
|
||
```http
|
||
GET /v1/stats/views?period=30d&group_by=day
|
||
```
|
||
|
||
#### 9.2.3 存储统计
|
||
```http
|
||
GET /v1/stats/storage
|
||
```
|
||
|
||
## 10. 用户管理 API
|
||
|
||
### 10.1 用户操作
|
||
|
||
#### 10.1.1 获取用户列表
|
||
```http
|
||
GET /v1/users?page=1&limit=20&role=all&status=active&search=admin
|
||
```
|
||
|
||
#### 10.1.2 创建用户
|
||
```http
|
||
POST /v1/users
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"username": "editor",
|
||
"email": "editor@example.com",
|
||
"password": "password123",
|
||
"role": "editor",
|
||
"display_name": "编辑者",
|
||
"is_active": true
|
||
}
|
||
```
|
||
|
||
#### 10.1.3 更新用户
|
||
```http
|
||
PUT /v1/users/{id}
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"display_name": "高级编辑者",
|
||
"role": "admin",
|
||
"is_active": true
|
||
}
|
||
```
|
||
|
||
#### 10.1.4 删除用户
|
||
```http
|
||
DELETE /v1/users/{id}
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
### 10.2 用户会话管理
|
||
|
||
#### 10.2.1 获取用户会话
|
||
```http
|
||
GET /v1/users/{id}/sessions
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
#### 10.2.2 强制下线
|
||
```http
|
||
DELETE /v1/users/{id}/sessions/{session_id}
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
## 11. 错误处理
|
||
|
||
### 11.1 错误码定义
|
||
|
||
| 错误码 | HTTP状态码 | 说明 |
|
||
|--------|------------|------|
|
||
| VALIDATION_ERROR | 400 | 请求参数验证失败 |
|
||
| AUTHENTICATION_REQUIRED | 401 | 需要认证 |
|
||
| INVALID_TOKEN | 401 | 无效的令牌 |
|
||
| TOKEN_EXPIRED | 401 | 令牌已过期 |
|
||
| PERMISSION_DENIED | 403 | 权限不足 |
|
||
| RESOURCE_NOT_FOUND | 404 | 资源不存在 |
|
||
| RESOURCE_CONFLICT | 409 | 资源冲突 |
|
||
| UNPROCESSABLE_ENTITY | 422 | 数据处理失败 |
|
||
| RATE_LIMIT_EXCEEDED | 429 | 请求频率超限 |
|
||
| INTERNAL_SERVER_ERROR | 500 | 服务器内部错误 |
|
||
| SERVICE_UNAVAILABLE | 503 | 服务不可用 |
|
||
|
||
### 11.2 错误响应示例
|
||
|
||
#### 11.2.1 验证错误
|
||
```json
|
||
{
|
||
"success": false,
|
||
"code": 400,
|
||
"message": "Validation failed",
|
||
"error": {
|
||
"type": "VALIDATION_ERROR",
|
||
"details": [
|
||
{
|
||
"field": "title",
|
||
"message": "Title is required",
|
||
"code": "REQUIRED"
|
||
},
|
||
{
|
||
"field": "email",
|
||
"message": "Invalid email format",
|
||
"code": "INVALID_FORMAT"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 11.2.2 权限错误
|
||
```json
|
||
{
|
||
"success": false,
|
||
"code": 403,
|
||
"message": "Permission denied",
|
||
"error": {
|
||
"type": "PERMISSION_DENIED",
|
||
"details": {
|
||
"required_permission": "photo.delete",
|
||
"user_role": "editor"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 11.2.3 资源不存在
|
||
```json
|
||
{
|
||
"success": false,
|
||
"code": 404,
|
||
"message": "Resource not found",
|
||
"error": {
|
||
"type": "RESOURCE_NOT_FOUND",
|
||
"details": {
|
||
"resource_type": "photo",
|
||
"resource_id": 999
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 12. API 限流
|
||
|
||
### 12.1 限流策略
|
||
|
||
| 端点类型 | 限制 | 时间窗口 |
|
||
|----------|------|----------|
|
||
| 认证端点 | 5次/IP | 1分钟 |
|
||
| 上传端点 | 10次/用户 | 1分钟 |
|
||
| 搜索端点 | 60次/用户 | 1分钟 |
|
||
| 一般端点 | 1000次/用户 | 1小时 |
|
||
| 管理端点 | 500次/用户 | 1小时 |
|
||
|
||
### 12.2 限流响应头
|
||
|
||
```http
|
||
X-RateLimit-Limit: 1000
|
||
X-RateLimit-Remaining: 999
|
||
X-RateLimit-Reset: 1642636800
|
||
X-RateLimit-Window: 3600
|
||
```
|
||
|
||
### 12.3 限流超出响应
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"code": 429,
|
||
"message": "Rate limit exceeded",
|
||
"error": {
|
||
"type": "RATE_LIMIT_EXCEEDED",
|
||
"details": {
|
||
"limit": 1000,
|
||
"window": 3600,
|
||
"reset_at": "2024-01-15T11:00:00Z"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 13. WebHook API
|
||
|
||
### 13.1 WebHook 配置
|
||
|
||
#### 13.1.1 创建 WebHook
|
||
```http
|
||
POST /v1/webhooks
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"url": "https://example.com/webhook",
|
||
"events": ["photo.created", "photo.updated", "photo.deleted"],
|
||
"secret": "webhook_secret_key",
|
||
"is_active": true
|
||
}
|
||
```
|
||
|
||
#### 13.1.2 WebHook 事件类型
|
||
|
||
| 事件类型 | 描述 | 数据载荷 |
|
||
|----------|------|----------|
|
||
| photo.created | 照片创建 | 完整照片数据 |
|
||
| photo.updated | 照片更新 | 更新后的照片数据 |
|
||
| photo.deleted | 照片删除 | 删除的照片ID |
|
||
| category.created | 分类创建 | 完整分类数据 |
|
||
| category.updated | 分类更新 | 更新后的分类数据 |
|
||
| category.deleted | 分类删除 | 删除的分类ID |
|
||
| user.login | 用户登录 | 用户基本信息 |
|
||
| system.backup | 系统备份 | 备份状态信息 |
|
||
|
||
### 13.2 WebHook 载荷示例
|
||
|
||
```json
|
||
{
|
||
"event": "photo.created",
|
||
"timestamp": "2024-01-15T10:30:00Z",
|
||
"data": {
|
||
"id": 1,
|
||
"title": "城市夜景",
|
||
"status": "published",
|
||
"created_at": "2024-01-15T10:30:00Z"
|
||
},
|
||
"signature": "sha256=abcdef123456..."
|
||
}
|
||
```
|
||
|
||
## 14. API 版本控制
|
||
|
||
### 14.1 版本策略
|
||
|
||
- **URL 版本控制**: `/v1/`, `/v2/`
|
||
- **向后兼容**: 至少支持2个主版本
|
||
- **废弃通知**: 通过响应头通知
|
||
|
||
### 14.2 版本响应头
|
||
|
||
```http
|
||
API-Version: 1.0
|
||
API-Deprecated: false
|
||
API-Sunset: 2025-01-15T00:00:00Z
|
||
```
|
||
|
||
### 14.3 版本变更日志
|
||
|
||
#### 版本 1.0.0 (当前)
|
||
- 初始 API 版本
|
||
- 支持照片、分类、标签管理
|
||
- 用户认证和权限控制
|
||
|
||
#### 版本 1.1.0 (计划)
|
||
- 添加 AI 标签推荐
|
||
- 支持视频文件
|
||
- 增强搜索功能
|
||
|
||
## 15. 总结
|
||
|
||
这个API接口设计文档提供了摄影作品集网站的完整API规范,包括:
|
||
|
||
### 🎯 设计特点
|
||
- **RESTful 风格**: 符合REST架构原则
|
||
- **统一响应格式**: 标准化的JSON响应
|
||
- **完整的CRUD操作**: 支持所有资源的增删改查
|
||
- **灵活的查询**: 丰富的筛选、排序、搜索功能
|
||
|
||
### 🔒 安全机制
|
||
- **JWT认证**: 基于令牌的认证机制
|
||
- **权限控制**: 细粒度的角色权限管理
|
||
- **请求限流**: 防止API滥用
|
||
- **数据验证**: 严格的输入验证
|
||
|
||
### 📊 功能丰富
|
||
- **文件上传**: 支持单文件、多文件、分块上传
|
||
- **图片处理**: 自动生成多种格式和尺寸
|
||
- **全文搜索**: 强大的搜索和筛选功能
|
||
- **统计分析**: 详细的数据统计和趋势分析
|
||
|
||
### 🛠️ 开发友好
|
||
- **详细文档**: 完整的接口说明和示例
|
||
- **错误处理**: 清晰的错误码和错误信息
|
||
- **版本控制**: 科学的API版本管理
|
||
- **WebHook支持**: 事件驱动的集成能力
|
||
|
||
这个API设计为Golang后端实现提供了完整的接口规范,可以支持前端和管理后台的所有功能需求。 |