翻译自 API Design Guide - Compatibility

本章提供了有关版本控制部分中给出的破坏和保持兼容性修改的详细说明。

并不总是绝对清楚什么是不兼容的修改,这篇指南 应该(should) 被当成参考性的,而不是覆盖到所有情况。

下面列出的这些规则只涉及客户端兼容性,默认 API 作者了解部署(包括实现细节的变化)的需求。

一般的目标是服务端升级 minor 或 patch 不能影响客户端的兼容性:

  • 代码兼容:针对 1.0 编写的代码在 1.1 上编译失败

  • 二进制兼容:针对 1.0 编译的代码与 1.1 客户端的库链接/运行失败(具体的细节依赖客户端,不同情况有不同变化)

  • 协议兼容:针对 1.0 构建的程序与 1.1 服务端通信失败

  • 语义兼容:所有组件都能运行但产生意想不到的结果

简而言之:旧的客户端应该与相同 major 版本的新服务端正常工作,并且能够轻松地升级到新的 minor 版本。

由于客户端使用了自动生成和手写的代码,除了理论上的基于协议的考虑,还有一些实际的问题。通过生成新版本的客户端库来测试你的修改,并保证测试通过。

下面的讨论将 proto 信息分为三类:

  • 请求信息(例如 GetBookRequest

  • 响应信息(例如 ListBooksResponse

  • 资源信息(例如 Book,包括在其他资源消息中使用的任何消息)

这三类有不同的规则,例如请求信息只会从客户端发送到服务端,响应信息只会从服务端发送到客户端,但资源信息一般会在两者之间互相发送。尤其是可被修改的资源需要根据读取/修改/写入的循环来考虑。

保持向后兼容的修改

向 API 服务中添加 API 接口

从协议的角度看,这种修改总是安全的。唯一需要考虑的是客户端库可能已经通过手写的代码使用了新 API 接口的名字。如果新接口与其它完全正交,这种情况不太可能发生。如果是已存接口的简化版本,则很可能引起冲突。

向 API 接口中添加方法

除非添加了一个与现有客户端库中方法冲突的方法,这种修改没有问题。

一个会破坏兼容性的例子:如果有 GetFoo 方法,C# 代码生成器已经创建了 GetFooGetFooAsync 方法。因此从客户端角度来看,在 API 接口中添加 GetFooAsync 方法将会破坏兼容性。

向方法添加 HTTP 绑定

假设绑定没有引入任何歧义,使服务端响应以前被拒绝的 URL 是安全的。当将现有操作应用于新的资源名称时,可能(may) 会这样做。

向请求信息添加字段

添加请求字段可以是兼容的,只要不指定该字段的客户端在新版本中与旧版本表现相同。

会导致错误的最明显例子是分页:如果 API 的 v1.0 版本不支持,除非 page_size 默认值是无穷大(这样是不好的)才能在 v1.1 中加入分页。否则 v1.0 的客户端原本希望通过一次请求取得所有结果,但实际只能取到一部分。

向响应信息添加字段

只要不改变其他响应字段的行为,就可以扩展不是资源的响应消息(例如ListBooksResponse),而不会破坏兼容性。即使导致冗余,任何在旧的响应消息中的字段也应该存在于新的响应中并保持它原来的语义。

例如,1.0 中的一个查询请求的响应有 bool 类型的字段 contained_duplicates 来指示因为重复而忽略掉的结果。在 1.1 中,我们在 duplicate_count 字段中提供更详细的信息,尽管从 1.1 版本来看是多余的,但 contained_duplicates 字段 必须(must) 要保留。

向枚举添加值

只在请求信息中使用的枚举类型可以自由扩展来添加新元素。例如,使用资源视图时,新的视图能够添加到新 minor 版本中。客户端从来不需要接收此枚举,所以也不需要关心它。

对于资源消息和响应消息,默认假设客户端应该处理它意识不到的枚举值。但是 API 作者应该意识到编写能够正确处理新枚举值的代码可能是困难的。应该(should) 在文档中记录当遇到未知枚举值时客户端的期望行为。

proto3 允许客户端接收它们不关心的值并且当执行重新序列化消息时会保持值不变,所以这样就不会打破读取/修改/写入循环的兼容性。JSON 格式允许发送数值,其中该值的“名称”是未知的,但是服务端通常不会知道客户端是否真正知道特定值。因此 JSON 客户端可能知道它们已经收到了以前对他们未知的值,但他们只会看到名称或数字而不是两个都有。在读取/修改/写入循环中将相同的值返回给服务端不应该修改这个值,因为服务端应该理解这两种形式。

添加只输出(output-only)的资源字段

可以(may) 添加仅由服务端提供的资源实体中的字段。服务端 可以(may) 验证请求中的值是否有效,但是如果该值被省略则 一定不能(must not) 失败。

破坏向后兼容的修改

删除/重命名服务、接口、字段名、方法或枚举值

从根本上说,如果客户端代码使用了某些字段,那么删除或重命名它将会破坏兼容性,并且 必须(must) 增加 major 版本号。引用旧名称的一些语言(如 C# 和 Java)在编译时会失败, 另一些语言会引起运行时异常或数据丢失。协议格式的兼容性在这里是无关紧要的。

修改 HTTP 绑定

这里的修改实际指删除添加。例如,你想要支持 PATCH,但已发布的版本支持 PUT,或者已经使用了错误的自定义动词,你 可以(may) 添加新的绑定,但是 一定不要(must not) 移除旧的,因为和删除服务的方法一样会破坏兼容性。

修改字段类型

尽管新类型是协议兼容的,能够改变客户端库自动生成的代码,因此 必须(must) 要升级 major 版本。会导致需要编译的静态类型的语言在编译期就发生错误。

修改资源名的格式

资源 一定不能(must not) 修改名字-这意味着集合名不能被修改。

不像其他大多数破坏兼容性的修改,这会影响 major 版本号:如果客户端期望使用 v2.0 访问在 v1.0 中创建的资源(或反过来),则应该在两个版本中使用相同的资源名称。

对资源名的验证也 不应该(should not) 改变,原因如下:

  • 如果验证变严格,之前成功能请求现在可能会失败

  • 如果比之前文档中记录的验证要宽松,依据之前文档的客户端可能会被破坏。客户端很可能在其他地方保存了资源名,并且对字符集和名字的长度敏感。或者,客户端可能会执行自己的资源名称验证来保持与文档一致。(例如,当开始支持 EC2 资源的长 ID 时,亚马逊向用户发出了许多警告并提供了迁移的时间)

请注意这样的修改只能在 proto 的文档中可见。因此当评审 CL 时审查除注释外的修改是不够的。

修改已有请求的可见性(visible behavior)

客户端总是依赖 API 的行为和语义,即使没有明确支持或记录此行为。因为在大多数情况下修改 API 的行为和语义在客户端看来是破坏性的。如果某行为不是加密隐藏的,你 应该(should) 假设用户已经依赖它了。

因为这个原因加密分页 token 是个好主意,以防止用户创建自己的 token,以及防止当 token 行为发生变化时可能带来的不兼容性。

在 HTTP 定义中修改 URL 格式

除了上面列出的资源名称的变化,这里还要考虑两种类型的修改:

  • 自定义方法名:虽然不是资源名称的一部分,但自定义方法名称是 REST 客户端 POST 请求 URL 的一部分。更改自定义方法名称不应该破坏 gRPC 客户端,但是公共 API 必须假定它们具有 REST 客户端。

  • 资源参数名:从 v1/shelves/{shelf}/books/{book}v1/shelves/{shelf_id}/books/{book_id} 的修改不会影响替代的资源名称,但可能会影响代码生成。

在资源消息中添加读/写字段

客户端会经常执行读取/修改/写入的操作。大多数客户端不支持它们意识不到的字段值,特别是 proto3 不支持。你可以指定任意消息类型(而不是原始类型)中缺失的字段表示更新时不会被修改,但这样使删除这样的字段变的困难。原始类型(包括 stringbytes)不能简单地使用这种方法,因为明确地设置 int32 的值为 0 和不对它设置值在 proto3 中并没有区别。

使用字段掩码来进行所有更新操作不会有问题,因为客户端不会隐式覆盖其不知道的字段。然而这是一个不寻常的决定,因为大部分 API 允许全部资源被更新。

查看其他章节

Google API 设计指南-兼容性相关推荐

  1. Google API 设计指南-设计模式

    翻译自 API Design Guide - Design Patterns 空响应体 标准的 Delete 方法 必须(must) 返回 google.protobuf.Empty 来实现全局一致性 ...

  2. Google API 设计指南 - 前言

    原文地址:https://cloud.google.com/apis... Copyright: Creative Commons Attribution 3.0 License Current Ve ...

  3. google api设计指南-简介

    简介 这是联网 API 的通用设计指南.它自 2014 年起在 Google 内部使用,是 Google 在设计 Cloud API 和其他 Google API 时遵循的指南.此设计指南在此处共享, ...

  4. RESTful API 设计指南[转]

    一种软件架构风格.设计风格,而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制. RESTful AP ...

  5. 组件接口(API)设计指南-文件夹

    组件接口(API)设计指南-文件夹 组件接口(API)设计指南[1]-要考虑的问题 组件接口(API)设计指南[2]-类接口(class interface) 组件接口(API)设计指南[3]-托付( ...

  6. RESTful API 设计指南 (转)

    RESTful API 设计指南 2016-02-23 ImportNew (点击上方公号,可快速关注) 作者:阮一峰 链接:http://www.ruanyifeng.com/blog/2014/0 ...

  7. RESTful API 设计指南

    原文地址:http://www.ruanyifeng.com/blog/2014/05/restful_api.html RESTful API 设计指南 作者: 阮一峰 日期: 2014年5月22日 ...

  8. 服务端指南 | 良好的 API 设计指南

    设计一套良好的 API 接口. 原文地址:服务端指南 | 良好的 API 设计指南 博客地址:blog.720ui.com/ 版本号 在 RESTful API 中,API 接口应该尽量兼容之前的版本 ...

  9. HTTP API 设计指南(基础部分)

    为了保证持续和及时的更新,强烈推荐在我的Github上关注该项目,欢迎各位star/fork或者帮助翻译 前言 这篇指南介绍描述了 HTTP+JSON API 的一种设计模式,最初摘录整理自 Hero ...

  10. Android的Google官方设计指南(上)

    Android 设计规范 本文章是我公司一个大牛之前的公司同事翻译的Android的Google官方设计指导,经过我整理而成,分享给大家,欢迎转载,但是请保留出处和翻译作者.本指导内容详实.规范,无论 ...

最新文章

  1. 关于java设计模式笔记
  2. C语言库函数大全及应用实例七
  3. Little Sub and AA
  4. GCD Counting
  5. extjs--combox用法
  6. 深入LINQ | 揭开IQueryable的面纱
  7. pythonrequests说明_解决Python requests 报错方法集锦
  8. dhcp获取i需要trunk_Cisco三层交换上给不同Vlan配置不同的DHCP
  9. 程序员如何成为编程高手并以此创业
  10. 大数据之-Hadoop之HDFS_HDFS组成架构---大数据之hadoop工作笔记0050
  11. 从汇编的眼光看C++(之delete内存泄露)
  12. wps文字表格制作拼音田字格模板_用word2003表格快速制作拼音田字格的方法.doc
  13. 常见电脑故障处理方法
  14. 3. 空实例对象调用静态方法的结果
  15. 数据库系统原理学习笔记三(关系数据模型的组成要素)
  16. cURL – POST请求示例
  17. 投影法快速求二叉树的三种遍历
  18. 浅入浅出Javac编译原理——爪哇岛探险(1)
  19. 百度如流新版发布,“流式办公”跳出在线办公模式“围城”
  20. 以太坊钱包私钥爆破产业链和攻击案例

热门文章

  1. js最基础知识回顾1(参数,函数,网页换肤)
  2. 程序员:如何成为一个全栈的工程师? 1
  3. *为需要读写VRML(.wrl)文件的同志们指点一条路
  4. java搜索引擎: lucene学习笔记 3
  5. 关于opacity、visibility、display属性的一道CSS面试题
  6. asp 读取 json 数据
  7. 【转】c语言位域操作—_结构体内冒号:的使用
  8. 2015百度之星资格赛.1004放盘子(数学推导)
  9. 第五章 APP元素定位
  10. SingleSignOn的配置和说明