原文地址:http://www.infoq.com/cn/news/2017/09/How-versioning-API

如何版本化API需要考虑各种实际业务场景,但是一个完备的API应该是:

  • 和客户端交互的约定。API需要确保稳定性,预先定义各种可能返回状态,包括各种异常。客户端无需考虑约定之外的情况。
  • 向下兼容。在API没有变化的时候,API实现的更新和升级,都应该确保原有客户端请求不出现问题。
  • RESTful。API设计应该能够遵照RESTful风格,通过URI来表示资源,通过HTTP GET、POST、PUT、DELETE等方法表示操作行为。

为了满足上述约定,版本化API不失为一种保持兼容性的好方法。版本化API的通常方式有:

URI中设置版本

这种方式通常在URI中增加一段用于标识版本,例如/v1/v2等。例如:

curl https://example.com/api/v2/lists/3

这种方式的优势在于版本信息很容易明显的看出来,可以通过浏览器直接访问。

HTTP头中设置版本

这种方式的版本信息会放在HTTP的请求头中,通常会利用Accept字段,或者自定义一个字段。例如:

curl https://example.com/api/lists/3 \
-H 'Accept: application/vnd.example.v2+json'

这种方式的好处是当版本升级时,URI保持不变,并且仅用于表示资源定位。

没有版本

版本化的目的是为了标识API的变化,如果API不会变化,或者每次都会重新扩展新的API,这种情况下,就可以标识版本信息。例如:

curl https://example.com/api/lists/3

一种折中方案

前面提到了三种版本化API的方式,通常情况下需要针对自己业务的特殊性来挑选其中的一种方式。但是,在实际应用场景中,情况会更加复杂,API的升级通常有两种情况:

  1. 大版本更新,例如字段类型变更、数据对象变更等。这种情况下无法满足对客户端的向下兼容,因此需要修改版本号。
  2. 小版本更新,例如增加可选参数、增加返回字段等。这种情况对于新客户端可以增加功能,对于老客户端仍然可以保持原有功能,可以不修改版本号。

因此,本文提出的折中方案是基于URI中的大版本号和HTTP头中的小版本号整合的方式。下面通过一个简单的示例来解释。

用户管理平台

一个常用的用户管理平台,提供以下API,通过用户ID获取用户信息:

curl https://example.com/api/v1/user/1
...
{
"id": 1,
"name": "test",
"email": "test@example.com"
}

考虑以下两种变动情况:一种是用户id从数字变成了字符串,另一种是新增一个用户头像的值。

前者修改因为数据类型的变化,会导致客户端解析出现问题。因此这样的修改已经破坏了向下兼容性,此时就需要修改API的版本号。例如:

curl https://example.com/api/v2/user/1
...
{
"id": "1",
"name": "test",
"email": "test@example.com"
}

第二种情况,对于旧客户端来说,只是增加了不使用的字段,通常的JSON格式解析库都可以忽略这些不使用的字段。对于新客户端则可以读取新的字段。例如:

curl https://example.com/api/v2/user/1
...
{
"id": "1",
"name": "test",
"email": "test@example.com",
"avatar": "http://example.com/1.jpg"
}

这种情况下,基本可以做到向下兼容,因此可以算是“小版本升级”。针对小版本升级,可以将小版本号放到HTTP头中。例如:

curl https://example.com/api/v2/user/1 \
-H 'API-VERSION: 20170801'
...
{
"id": "1",
"name": "test",
"email": "test@example.com",
"avatar": "http://example.com/1.jpg"
}

后端路由

由于混合版本化的方式同时涉及到URI和HTTP头字段,前端代理(例如HAProxy、nginx)可以通过这些特定版本号字段将请求代理到对应的后端应用。

例如,前端使用HAProxy进行多版本分发,可以针对URI和HTTP头定制acl,然后再对这些acl进行组合,设置不同的backend。

acl is_v1 path_beg /api/v1
acl is_v2 path_beg /api/v2
acl is_version_1 hdr(API-VERSION) 20170801
acl is_version_2 hdr(API-VERSION) 20170701
use_backend old_server if is_v1 is_version_1
use_backend new_server if is_v2 is_version_2
backend old_server
...
backend new_server
...

这样可以将API版本化规则应用到不同的后端,以保证向下兼容性。

总结

基于本文版本化API规则,将“大版本”应用在URI上,将“小版本”应用在HTTP头字段上。通常来说,如果API升级之后破坏了向下兼容性,就应该升级“大版本”号;如果API升级可以向下兼容,可以升级“小版本”号。

版本化API有很多不同的设计方式,本文仅是其中一种。实际应用时,还是要根据业务场景进行选择,包括API版本升级频率,API稳定性等。通过HAProxy、nginx等代理服务,可以在确保向下兼容的情况下,由业务方决定老版本API的保留时间。

如何版本化你的API?--转的更多相关文章

  1. ABP 适用性改造 - 添加 API 版本化支持

    Overview 在前面的文章里有针对 abp 的项目模板进行简化,构建了一个精简的项目模板,在使用过程中,因为我们暴露的 api 需要包含版本信息,我们采取的方式是将 api 的版本号包含在资源的 ...

  2. IPFS - 可快速索引的版本化的点对点文件系统(草稿3)

    摘要 星际文件系统是一种点对点的分布式文件系统, 旨在连接所有有相同的文件系统的计算机设备.在某些方面, IPFS类似于web, 但web 是中心化的,而IPFS是一个单一的Bittorrent 群集 ...

  3. ArcGIS分支版本化( Branch Versioning )技术介绍

    概述 分支版本化技术是有别于传统的SDE版本化技术,它用于支持WebGIS模式下的多用户长事务编辑. 优势功能 使用分支版本化技术将获得以下功能 1. 支持长事务的编辑. 2. 支持Undo和Redo ...

  4. 旅图beta版 asp.net web api 单元测试

    旅图 beta版 asp.net web api 单元测试 测试接口:http://120.27.7.115:1010/Help 测试目的 对每个接口单元进行测试,保证每个接口的可靠性. 单元描述 注 ...

  5. 微信支付.NET版开发总结(JS API),好多坑,适当精简

    前2天,做一个手机网页的微信支付的项目,费了好些周折,记录一下.接下来,按照开发步骤,细数一下,我遇到的那些坑. [坑1]官方邮件中下载的demo只有PHP版本,其他版本没有给链接.可能让人误以为只有 ...

  6. 微信支付.NET版开发总结(JS API),好多坑,适当精简。

    前2天,做一个手机网页的微信支付的项目,费了好些周折,记录一下.接下来,按照开发步骤,细数一下,我遇到的那些坑. [坑1]官方邮件中下载的demo只有PHP版本,其他版本没有给链接.可能让人误以为只有 ...

  7. (翻译)Xamarin.Essentials 最新预览版的更多跨平台 API

    原文地址:https://blog.xamarin.com/cross-platform-apis-xamarin-essentials-latest-preview/ 在 Microsoft Bui ...

  8. php版网易视频云api

    最近在做在线教育课程,使用网易云视频作为在线视频直播. 网易官方只有java示例,我们使用php,就自己写个api. 当然实现也是很简单的. 演示:http://www.deitui.com/inde ...

  9. C#版-百度网盘API的实现(一)

    在这篇文章中,楼主将会给大家介绍一下,通过C# winform程序在后台模拟用户登陆百度网盘的基本思路 首先了解下模拟登陆的流程,如下: 一,访问http://www.baidu.com网站,获取BA ...

随机推荐

  1. 了解jQuery的$符号

    $是什么? 可以使用typeof关键字来观察$的本质. console.log(type of $); //输出结果为function 因此可以得出结论,$其实就是一个函数.$(); 只是根据所给参数 ...

  2. angular.js表单验证

    表单验证<AngularJs> 常用的表单验证指令 1. 必填项验证 某个表单输入是否已填写,只要在输入字段元素上添加HTML5标记required即可: <input type=& ...

  3. vue的计算属性get和set

    1.计算属性是用来存储数据,但具有以下几个特点: a.数据可以进行逻辑处理操作. b.对计算属性中的数据进行监视. 2.计算属性和普通属性的区别: a.计算属性是基于它的依赖进行更新的,只有在相关依赖 ...

  4. C++基础 (9) 第九天 编译器对模板类的二次编译 类模板 自定义数组类

    1 昨日回顾 2 编译器对于模板的二次编译 写一个模板函数 然后进行调用 g++ template.cpp -o template // 汇编 g++ -S template.cpp –o templ ...

  5. 51nod-完美字符串(贪心)

    约翰认为字符串的完美度等于它里面所有字母的完美度之和.每个字母的完美度可以由你来分配,不同字母的完美度不同,分别对应一个1-26之间的整数. 约翰不在乎字母大小写.(也就是说字母F和f)的完美度相同. ...

  6. linux 遇到(vsftpd)—500 OOPS:chroot

    今天在用vsftpd 时出现一个问题: 500 OOPS:chroot 解决办法: 1.关闭SELINUX [root@localhost ~]#vi /etc/sysconfig/selinux # ...

  7. jquery 去重

    var yearArray = new Array(2009, 2009, 2010, 2010, 2009, 2010); $.unique(yearArray); alert(yearArray) ...

  8. PHP学习总结(2)——PHP入门篇之PHP代码标识

    认识PHP代码标识 想在页面中编写PHP​代码非常容易,如下面代码: <?php echo "想学习php吗?来慕课网吧";?> 就像你可以编写JavaScript脚本 ...

  9. Mysql学习总结(37)——Mysql Limit 分页查询优化

    select * from table LIMIT 5,10; #返回第6-15行数据 select * from table LIMIT 5; #返回前5行 select * from table ...

  10. pycaffe 配置

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50967820 本文将继续接着上一篇博客 ...