# API 版本管理指南

## 📋 概述

小虾 SaaS 使用 URL 路径版本管理策略，确保 API 的向后兼容性。

---

## 🔢 版本命名规则

### 当前版本：v1

```
/api/v1/auth/login
/api/v1/workspaces
/api/v1/projects
```

### 版本号规则

- **v1, v2, v3...** - 主版本号
- 破坏性变更才升级主版本
- 非破坏性变更在当前版本迭代

---

## 📝 版本策略

### 什么时候升级版本？

**需要升级（破坏性变更）：**
- ✅ 修改响应结构
- ✅ 删除字段
- ✅ 修改字段类型
- ✅ 修改认证方式
- ✅ 修改 HTTP 方法

**不需要升级（兼容性变更）：**
- ✅ 添加新字段
- ✅ 添加新端点
- ✅ 添加可选参数
- ✅ 优化性能
- ✅ 修复 Bug

---

## 🔄 版本生命周期

### 阶段 1: 开发中（Development）
- 版本：`v2-beta`
- 状态：不稳定，可能变更
- 使用：仅内部测试

### 阶段 2: 稳定版（Stable）
- 版本：`v2`
- 状态：稳定，推荐使用
- 支持：完整支持，持续更新

### 阶段 3: 维护中（Maintenance）
- 版本：`v1`（当 v2 发布后）
- 状态：只修复安全问题和严重 Bug
- 支持：12 个月维护期

### 阶段 4: 已弃用（Deprecated）
- 版本：`v1`（维护期结束后）
- 状态：仍可访问，显示弃用警告
- 支持：6 个月弃用期

### 阶段 5: 下线（Sunset）
- 版本：`v1`（弃用期结束后）
- 状态：返回 410 Gone
- 支持：无

---

## 📅 版本时间线示例

```
2026-06-01: v1 发布 (Stable)
2027-01-01: v2 发布 (Stable)
2027-01-01: v1 进入维护期 (Maintenance, 12个月)
2028-01-01: v1 进入弃用期 (Deprecated, 6个月)
2028-07-01: v1 下线 (Sunset)
```

---

## 🚨 弃用通知

### 响应头

```http
HTTP/1.1 200 OK
X-API-Version: v1
X-API-Deprecated: true
X-API-Sunset-Date: 2028-07-01
X-API-Deprecation-Info: https://docs.xiaoxia-saas.com/api/deprecation/v1
```

### 响应体（可选）

```json
{
  "data": { ... },
  "_meta": {
    "deprecated": true,
    "sunset_date": "2028-07-01",
    "migration_guide": "https://docs.xiaoxia-saas.com/api/migration/v1-to-v2"
  }
}
```

---

## 🔧 客户端处理

### 检测弃用

```python
import requests

response = requests.get("https://api.xiaoxia-saas.com/api/v1/workspaces")

if response.headers.get("X-API-Deprecated") == "true":
    sunset_date = response.headers.get("X-API-Sunset-Date")
    print(f"警告: API v1 将在 {sunset_date} 下线")
```

### 自动迁移

```python
class APIClient:
    def __init__(self, version="v2"):
        self.version = version
        self.base_url = f"https://api.xiaoxia-saas.com/api/{version}"
    
    def fallback_to_v1(self, endpoint):
        """自动降级到 v1"""
        try:
            return self.request(endpoint)
        except APINotFoundError:
            # v2 不存在，尝试 v1
            self.version = "v1"
            return self.request(endpoint)
```

---

## 📚 迁移指南

### v1 → v2 迁移示例

**变更 1: 登录响应结构**

v1:
```json
{
  "token": "abc123",
  "user_id": "user-123"
}
```

v2:
```json
{
  "access_token": "abc123",
  "refresh_token": "def456",
  "expires_in": 1800,
  "user": {
    "id": "user-123",
    "email": "user@example.com"
  }
}
```

**迁移代码:**
```python
# v1
token = response.json()["token"]

# v2
token = response.json()["access_token"]
```

---

## 🛠️ 实现方式

### FastAPI 版本路由

```python
from fastapi import APIRouter

# v1 路由
api_v1 = APIRouter(prefix="/api/v1")

@api_v1.get("/workspaces")
async def list_workspaces_v1():
    return {"workspaces": []}

# v2 路由
api_v2 = APIRouter(prefix="/api/v2")

@api_v2.get("/workspaces")
async def list_workspaces_v2():
    return {
        "data": [],
        "pagination": {"page": 1, "total": 0}
    }

# 注册到主应用
app.include_router(api_v1)
app.include_router(api_v2)
```

### 弃用中间件

```python
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware

class DeprecationMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        response = await call_next(request)
        
        if request.url.path.startswith("/api/v1"):
            response.headers["X-API-Deprecated"] = "true"
            response.headers["X-API-Sunset-Date"] = "2028-07-01"
        
        return response
```

---

## 📊 版本使用统计

### 监控指标

```python
from prometheus_client import Counter

api_version_counter = Counter(
    'api_requests_by_version',
    'API requests by version',
    ['version']
)

@app.middleware("http")
async def track_version(request: Request, call_next):
    version = extract_version(request.url.path)
    api_version_counter.labels(version=version).inc()
    return await call_next(request)
```

### 查看统计

```bash
# v1 使用量
curl http://localhost:8000/metrics | grep api_requests_by_version{version="v1"}

# v2 使用量
curl http://localhost:8000/metrics | grep api_requests_by_version{version="v2"}
```

---

## 🎯 最佳实践

### 1. 提前通知

- 至少提前 6 个月通知弃用
- 通过邮件、公告、响应头多渠道通知
- 提供详细的迁移指南

### 2. 保持兼容

- 尽可能添加而不是修改
- 使用可选参数而不是必填
- 保留旧字段，添加新字段

### 3. 渐进式迁移

```
v1 (100%) → v1 (80%) + v2 (20%) → v1 (20%) + v2 (80%) → v2 (100%)
```

### 4. 文档优先

- 版本变更先更新文档
- 提供完整的迁移指南
- 包含代码示例

---

## 🔗 相关资源

- [语义化版本规范](https://semver.org/)
- [API 版本管理最佳实践](https://restfulapi.net/versioning/)
- [Stripe API 版本管理](https://stripe.com/docs/api/versioning)

---

**最后更新:** 2026-06-17
