浅谈 API 版本设计

李飞 于 2015-07-31

背景

从 Web 2.0 进入移动时代,对于服务端研发而言,一个比较大的变化就是日常的工作由开发一个一个的页面调整为开发不同的 API。

相对于页面,API 的一个不同点就是需要长期维护,需要引入版本的概念。这是因为 Natvie App 的升级并不如页面那么方便,当一个新功能上线后,对于页面而已,它已经完成了升级;而对于 App 而言,这个过程是缓慢且痛苦的,甚至数年后,旧版的应用还有少量用户在使用。

我们从两个方面来讨论 API 版本的设计风格:

  1. 版本的使用

  2. 版本的体现

如何使用版本

常见的版本选择方案有几种:

  1. 每个 API 使用独立的版本

  2. 所有的 API 共用一个版本

    1. 使用客户端版本作为 API 的版本

    2. API 独立一套版本系统

  3. 复合版本

版本是作用

当一个 API 不能向前兼容时,就需要引入版本,简单地说,就是旧版客户端使用新版的 API 会发生错误。如果一个 API 仅仅是增加了几个新的字段,旧版的客户端可以无障碍地使用新 API,那么不需要升级它的版本。频繁的升级 API 的版本是也是一种复杂度。

每个 API 使用独立的版本

这种 API 设计最为常见,也最符合实际情况。

提供订单和提供用户信息的 API 本来就是两件事情,升级订单的时候用户信息其实并没有更改,不应该随着订单 API 一起升级。

Note
这里需要阐述一个前提,API 的版本设计是 API 的设计风格的一部分,选择哪种 API 设计风格很大程度上会决定 API 的版本设计。常见的 API 的设计风格在《面向实体及其关系的范式 API 设计风格》一文中有阐述。

如果 API 设计风格是『套模板』API 设计,那么『每个 API 使用独立的版本』是完全没有问题,而且也是非常正确的一种选择。事实上,这种设计风格下,API 升级的主要来源是 Templates 的变化,Templates 的变化只与当前的 Templates 相关。

如果是采用『嵌入外键关系』或者『范式』API 设计风格的话,『每个 API 使用独立的版本』这种设计可能就会出现不便的地方。

Example 1. 例子

有两个 API,一个是提供用户信息的 API,一个是提供订单信息的 API,采用『嵌入外键关系』的API 设计风格。

用户 API
{
  "id": 10002,
  "name": "张三"
}
订单 API
{
  "id": 10001,
  "user": {
    "id": 10002,
    "name": "张三"
  },
  ...
}

此时,若调整用户的字段,把 name 字段调整为 user_name,那么用户和订单 API 都需要调整。而实际情况下,很难找到到底有哪些 API 返回了用户这个实体。即便是把所有相关的 API 都找到且升级了版本,客户端处理起来也是非常麻烦。

Warning
如果 API 的风格是独立的,没有任何关系,譬如 RESTful API,每个 API 只返回一个独立的资源,不与其他任何实体有联系,那么选择『独立的 API 版本』是合适的。

所有 API 共用一个版本

既然『每个 API 使用独立的版本』有很多不便之处,我们需要找到新的版本设计风格解决这些问题。『所有 API 共用一个版本』是一种不错的选择。

拿上面的例子来说,只有用户信息有调整,所有 API 包括用户和订单 API 都会普升一个版本。服务端的研发只需要维持一个版本到打包方式的映射关系:from_version, to_version ⇒ entity pack,而客户端的同学更省事,只需要调整一下当前配置文件中的 VERSION 即可。

这个设计风格下还有几个流派,采用客户端版本作为 API 的版本和 API 使用独立的版本系统。我的建议是如果你的 API 想给予不只一款客户端来使用的话,请选择后者。

Warning
『所有 API 共用一个版本』的设计风格的一个最大的缺点就是版本涨的太快。

复合版本策略

Note
API 实际上是提供了实体及其关系的数据接口(指的是非『套模板』设计风格),版本的概念不仅仅与实体有关,还与实体间的关系有关。

实体间的关系大部分都局限在专有的 API 中,它与实体不同,不会被其他 API 共享,最多会模块间共享。

『复合版本策略』就是说采用几种版本的复合值作为最终的 API 版本。譬如:各个模块下共用一个版本,每个实体使用一个版本,最终的效果是: module:1,user:1,order:2

这种 API 设计风格最理想,但是与『所有 API 共用一个版本』相比收益其实不大,但逻辑上相对复杂。

版本的体现

所谓『版本的体现』指的是客户端如何指定调用 API 的版本。下面列举了经常用到的一些版本设计风格:

当我们在讨论版本设计时,我们在讨论什么?

  1. 负载均衡友好

  2. 业务场景

results matching ""

    No results matching ""