Files
xiaoxia-saas/docs/API-VERSIONING.md
T
Xiaoxia AI c23922faab feat(api): add API versioning and deprecation strategy
- Implement API version management middleware
- Add version lifecycle management (dev/stable/maintenance/deprecated/sunset)
- Add deprecation warning headers (X-API-Deprecated, X-API-Sunset-Date)
- Add version tracking headers (X-API-Version)
- Handle sunset versions with 410 Gone response
- Comprehensive API versioning documentation
- Include migration guide and best practices
- Support gradual version rollout

Phase 4 Task 44/68 completed
2026-06-17 08:41:11 +08:00

304 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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