name: api-versioning description: 用于规划API版本化策略、处理破坏性变更或管理API弃用。涵盖URL、头部和查询参数版本化方法。 allowed-tools: Read, Glob, Grep
API 版本化
版本化API的策略、管理破坏性变更以及优雅地弃用旧版本。
何时使用此技能
- 选择API版本化策略
- 规划破坏性变更
- 弃用API版本
- 管理多个API版本
- 为API演进设计
为什么版本化API?
API是与客户的合约。
破坏性变更会破坏客户。
没有版本化:
- 更改字段名称 → 所有客户中断
- 删除端点 → 所有客户中断
- 更改行为 → 意外的客户行为
有版本化:
- 旧客户使用旧版本
- 新客户使用新版本
- 可能逐步迁移
版本化策略
URL路径版本化
https://api.example.com/v1/users
https://api.example.com/v2/users
优点:
- 清晰明确
- 易于理解
- 易于路由
- 易于缓存
缺点:
- 版本嵌入客户端代码
- 同一资源多个URL
- 非真正RESTful(URL应标识资源)
头部版本化
GET /users
Accept: application/vnd.example.v1+json
或自定义头部:
GET /users
API-Version: 1
优点:
- 干净的URL
- 更RESTful
- 版本与资源分离
缺点:
- 从URL隐藏
- 在浏览器中难以测试
- 需要头部支持
查询参数版本化
GET /users?version=1
GET /users?api-version=2023-01-01
优点:
- 易于添加
- 可选(可默认)
- 易于测试
缺点:
- 可能被遗忘
- 污染查询字符串
- 缓存复杂性
内容协商
Accept: application/vnd.example+json; version=1
优点:
- 标准HTTP机制
- 灵活
缺点:
- 实现复杂
- 难以发现
策略比较
| 策略 | 可见性 | 实现难度 | 缓存 | 推荐 |
|---|---|---|---|---|
| URL路径 | 高 | 容易 | 容易 | 最佳用于公共API |
| 头部 | 低 | 中等 | 中等 | 良好用于内部API |
| 查询参数 | 中等 | 容易 | 复杂 | 良好用于简单情况 |
| 内容协商 | 低 | 复杂 | 中等 | 很少使用 |
版本化方案
整数版本
v1, v2, v3
优点:简单,明确主要变更
缺点:粗粒度
最佳用于:公共API,破坏性变更不频繁
语义版本化
v1.2.3(主要.次要.补丁)
主要:破坏性变更
次要:新功能(向后兼容)
补丁:错误修复
优点:细粒度,可预测
缺点:更复杂
最佳用于:库,SDK
基于日期的版本化
2023-01-15, 2023-06-01
优点:清晰版本当前时间
缺点:不指示变更幅度
最佳用于:频繁变化的API(Stripe,GitHub)
示例(Stripe):
Stripe-Version: 2023-10-16
什么需要新版本?
破坏性变更(新主要版本)
总是破坏性:
- 删除端点
- 删除字段
- 更改字段类型
- 更改字段含义
- 重命名字段
- 添加必需字段
- 更改认证
- 更改错误格式
非破坏性变更(不需要版本)
安全变更:
- 添加新端点
- 添加可选字段
- 添加新枚举值
- 添加可选参数
- 放宽验证
- 添加新错误代码
版本管理
运行多个版本
选项1:独立代码库
/v1/* → v1服务
/v2/* → v2服务
优点:完全隔离
缺点:重复,维护负担
选项2:共享代码库分支
if (version == 1) {
return formatV1(data);
} else {
return formatV2(data);
}
优点:单一代码库
缺点:代码复杂性增长
选项3:转换层
内部模型 → 版本特定转换器 → 响应
优点:清晰分离
缺点:需要转换代码
版本路由
API网关模式:
客户端 → 网关 → 按版本路由 → 服务
网关职责:
- 从URL/头部解析版本
- 路由到适当后端
- 如果需要转换
- 处理默认值
弃用策略
生命周期阶段
1. 当前:活跃开发
2. 维护:仅错误修复
3. 弃用:无变更,宣布日落
4. 日落:移除
时间线示例:
v1:当前(12个月)
v1:v2启动时维护(6个月)
v1:弃用(6个月)
v1:日落
弃用通信
头部:
Deprecation: true
Sunset: Sat, 1 Jul 2024 00:00:00 GMT
Link: <https://api.example.com/v2/docs>; rel="successor-version"
响应体:
{
"data": {...},
"_deprecation": {
"message": "此API版本已弃用",
"sunset": "2024-07-01",
"successor": "https://api.example.com/v2"
}
}
迁移支持
提供:
1. 迁移指南记录所有变更
2. 旧 → 新端点映射
3. 常见操作代码示例
4. SDK更新与兼容层
5. 沙盒环境用于测试
最佳实践
默认版本
选项:
1. 要求显式版本(推荐用于公共API)
2. 默认最新(稳定性危险)
3. 默认最旧支持(保守)
推荐:要求版本,缺失时失败
响应中的版本
在响应中包含版本信息:
{
"data": {...},
"_meta": {
"api_version": "v2",
"deprecated": false
}
}
优雅降级
当版本未知时:
1. 返回错误并支持版本列表
2. 重定向到文档
3. 返回最新版本并警告
HTTP 400 错误请求
{
"error": "未知API版本",
"supported_versions": ["v1", "v2"],
"documentation": "https://docs.example.com/api"
}
测试多个版本
测试矩阵:
- 所有支持版本
- 破坏性变更边界
- 弃用警告
- 日落行为
自动化测试:
- 每版本合同测试
- 向后兼容性测试
- 迁移路径测试
真实世界示例
Stripe
基于日期:2023-10-16
头部:Stripe-Version
默认:账户的API版本
回滚:可固定到旧版本
升级:在仪表板预览
GitHub
基于日期:2022-11-28
头部:X-GitHub-Api-Version
默认:最新
预览功能:Accept头部
URL路径:/v1/, /v2/
每版本发现文档
长弃用周期(年)
Twilio
基于日期:2010-04-01
URL路径包含日期
非常长的支持窗口
反模式
1. 过多版本
→ 合并,设置弃用计划
2. 次要版本中的破坏性变更
→ 严格遵循语义版本化
3. 无弃用警告
→ 始终在破坏前沟通
4. 即时日落
→ 给客户时间迁移(最少6-12个月)
5. 每端点版本
→ 保持所有端点每版本同步
相关技能
api-design-fundamentals- API设计模式idempotency-patterns- 安全API操作quality-attributes-taxonomy- 可维护性属性