写点什么

HTTP API 可演进性最佳实践

  • 2012-02-05
  • 本文字数:1830 字

    阅读完需:约 6 分钟

正如标题所示,Benjamin Carlyle 试图在《Best Practices For HTTP API Evolvability》一文中为围绕 HTTP API 构建的系统的设计定义原则和实践,这些系统是可扩展的,并且能一直进化下去。他先指出了 REST(一种架构风格)和 HTTP API(通过 HTTP 暴露的编程接口)之间的区别。

HTTP API 是针对一个特定服务的面向开发者的接口,也被称为 RESTful 服务契约面向资源架构 URI Space

我说 REST 和 HTTP API 紧密相关是因为大多数 HTTP API 并不严格遵守统一接口约束,严格说来统一接口约束要求接口是“标准的”[…]

文章开头他标识出了 API 设计中的不同元素,这些元素决定了 API 后续的进化。通常来说,API 进化涉及到了设计客户端与服务器的兼容性;特别是 API 的向后和向前兼容变更。 变更频率按增序排列依次是:

  1. API 中用到的方法的通用语义,包含异常条件和其他元数据
  2. API 中用到的媒体类型的通用语义,包含全部 Schema 信息
  3. 构成 API 的 URI 集合,包含 API 中用到的每个通用方法和媒体类型的特定语义

API 进化中改变最少的就是方法的语义。文中描述的最佳实践是识别出向前和向后兼容的变化,运用 Postel 法则让服务与客户端以一种更能容忍的方式进行进化。他建议尽可能地使用 HTTP 错误码来传达兼容性问题。

最佳实践 3:新方法名应该选择那些不会和任何已有方法发生向前兼容的名字。例如,如果要处理的方法必须正确理解(必须理解语义)方法的新特性,那么应该选择一个新的方法名。

最佳实践 4:服务应该忽略它们不理解的标头或组件。代理应该不加修改地传递这些标头,或者是无法理解的组件。

[…]

最佳实践 7:在某个数字范围内为新状态分配一个状态码,这个范围可以粗粒度地标识已存在的条件。

[…]

最佳实践 9:如果新状态是一个已知状态(除了 400 Bad Request 或 500 Internal Server Error)的子集,可以向响应头添加信息来细化已知状态的含义,而不是分配一个新的状态码。

他指出了一个重要的区别,即客户端与服务器交互中媒体类型的对称本质。

[…] 与客户端和服务器之间非对称的方法和状态不同,媒体类型通常能用作请求或响应的负载,即适用于两个方向。为此本节中我们不讨论客户端与服务器,而是讲发送端与接收端。

…这构成了与媒体类型相关的最佳实践的基础

[…]

最佳实践 11:只有当验证逻辑是为与文档发送方相同版本或后续版本的 API 编写的情况下,才可能出现不符合最佳实践 10 的文档验证。

最佳实践 12:在不违反媒体类型设计目标的前提下,如果能向现有媒体类型的 Schema 中添加新信息,那么就添加吧。

他提倡使用 Content-Types 和 Accept 标头来管理发送端与接收端之间的兼容性。

HTTP API 习惯于做出向后不兼容的媒体类型 Schema 变更。新客户端请求或者提供了 Schema 中带有向后不兼容变更的新媒体类型。老的客户端继续请求或提供旧的媒体类型。直到所有重要的相关实现都升级到最新的媒体类型集之前,客户端与服务器端都应该要支持旧的媒体类型。

他认为对资源的修改,尤其是 URI 的修改都是服务器应该关心的事;如果客户端是设计成由超媒体约束驱动的话,一般这些修改都不应该引入兼容性问题。他提倡使用 Cookies 将客户端请求路由到合适的服务实例 / 服务器。

在使用多种通用方法时,我们不再处理通用的方法或媒体类型,而是和带有特定语义的特定 URL 打交道。[…] 在考虑如下服务契约时,我倾向于采用以服务器为中心的视角:

  • GET /invoice/{invoice-id},返回媒体类型 application/invoice+xml,内容是 invoice-id 指定的发货单
  • GET /invoice/{invoice-id}/paid,返回媒体类型 text/plain( xsd:bool 语法),内容是 invoice-id 指定的发货单的支付状态
  • PUT /invoice/{invoice-id}/paid,接受媒体类型 text/plain( xsd:bool 语法),设置 invoice-id 指定的发货单的支付状态

此外,他还提出了一些客户端的最佳实践,以便客户端能应对服务器 URI 的转变(transition)和进化。

最佳实践 19:在升级时,服务应该通过 Cookies 追踪哪些客户端应该连接到旧的服务器,哪些应该连接到新的服务器,或者也可以使用类似的机制。

最佳实践 20:即使不是在响应 HEAD 或 GET 请求,客户端也应该遵从服务器发回的重定向状态响应 [说明: RFC2616 ]

最佳实践 21:重新设计 URL 时,确保新的 URL 拥有和旧 URL 一样的语义,并将旧 URL 重定向到新的 URL 上。

本文中提供了一些基本原理,让 HTTP API 系统能随着时间不断进化。请务必阅读 Benjamin Carlyle 的完整原文以便对这一主题能有更深入的理解。

查看英文原文: Best Practices For HTTP API Evolvability

2012-02-05 09:163735
用户头像

发布了 135 篇内容, 共 64.0 次阅读, 收获喜欢 43 次。

关注

评论

发布
暂无评论
发现更多内容

做成事情,唯有实干,没有捷径

Yolanda

疫情故事一则 | 庆祝北京应急响应调为二级

赵新龙

滴滴 顺风车

一文学会设计模式

泰伦卢

c++ 互联网 极客 设计模式 架构模式

程序猿 Windows 10 日常使用软件推荐

夏天

程序员 日常软件 windows

回"疫"录(7):关键时刻稳住别浪

小天同学

疫情 回忆录 现实纪录 纪实

从“中国GPL诉讼第一案”聊聊开源软件的license许可证

赵新龙

GitHub 开源 许可证

小小说

冯夷

Firefox浏览器背后的力量,Mozilla基金会的“生财”之道

赵新龙

firefox 开源 基金会

怎样打造用户喜爱的产品

孙苏勇

思考 产品设计 读书

Angular的遍历,默写一遍。

玉龙BB

大前端 angular 前后端分离 集合

「颜值即正义」那些管UI小姐姐要来的网站

童欧巴

CSS 效率工具 大前端 UI

万物皆逝

冯夷

生活

如何表达自己的感情?

zkh

技术“大跃进”进行中

冯夷

基础设施

ELK环境搭建

Geek_0o5u34

elasticsearch Logstash Kibana ELK

高并发下作余额扣减的一些经验

流沙

后端

设计一个地铁路线规划小工具

流沙

开源 后端

有问必答(2020-03-28):活着是为了什么?

冯夷

生活

有问必答(2020-04-23):为什么读书?怎么读书比较高效?

冯夷

你问我答

有问必答(2020-04-24):如何做时间管理/任务管理?

冯夷

你问我答

Windows中使用vagrant+virtual box创建Docker

Java收录阁

Docker vagrant

在 VPS 里搭建 Drone CI 持续集成构建系统

Gadzan

Docker ci DevOps cicd 持续集成

如何写作一本书(1):写前须知

英子编辑

技术 写作 读书

关于需求评审和讲解的一些思考

Yezhiwei

使用Vue+Highcharts绘制中国地图

kos

Vue 大前端

一篇文章教你服务器OOM后如何快速定位处理问题

Java OOM 系统故障

MongoDB入门笔记

编程随想曲

sql mongodb

我的第一个 100K app

道哥

ios swift 自由职业 独立开发者 App

使用Kubeadm搭建Kubernetes集群

Java收录阁

Kubernetes k8s

媒体的经营 04 | 难在:有所表达,影响决策

邓瑞恒Ryan

创业 媒体 技术社区

Spring IOC 和 DI

再见孙悟空

spring

HTTP API可演进性最佳实践_REST_Dilip Krishnan_InfoQ精选文章