REST Architectural Constraints

REST代表了Representational State Transfer(表述性状态传递),一个由Roy Fielding在2000年创造的名词,是一种通过HTTP用来设计松散耦合应用的设计体系风格,通常被用来开发web service。REST并不强制任何有关如何在底层实现的规则,它仅仅提出了高层设计的方针并且让开发者去思考如何去实现。

在我最近一次的工作中,我为一家电信公司设计了2年的RESTful API、在这篇文章里,我将会分析我的一些从实际开发经验中总结的一些思考。你可能不同意其中的几点,但是这没关系,我乐意以开放的心态来与你讨论这些事。

让我们从标准设计的具体内容开始,来理解Roy Fielding到底想让我们如何去做。然后再来讨论一些我的想法使得你的RESTful API设计更加精益求精。

Architectural Constraints

REST定义了6个可用于任何web服务(一个真正的RESTful API)的体系约束

  1. 统一接口
  2. 客户端-服务器模式
  3. 无状态
  4. 可缓存
  5. 分层系统
  6. 写满足需求的代码(可选)

统一接口

顾名思义,你必须决定对于系统内部资源的API接口,并且将这些接口暴露给API的消费者。每个系统内的资源应当仅有一个对应的逻辑URI,并且提供一个方法来获取相关或附加数据。将一种资源与一个URL地址关联起来总是最好的。

译者注:

API的消费者(API consumers)即为使用该API的人。

将一种资源与一个URL地址关联起来总是最好的,原句为:

It’s always better to synonymies a resource with a web page.

原句指的是将一种资源与web page做同义替换,但译者认为此处的web page其实指的应当就是一个单独的URL

任何单个资源都不应该太大或者在它的表现层(representation)里包含了所有的东西。无论何时相关,一个资源都应当包含一个链接(HATEOAS),指向一个用来获取相关信息的URI。

同时,系统间的资源的表现层应当遵循一个特定的准则,例如命名规范,链接格式或数据格式(xml或Json)等。

所有的资源都应当可以通过一个通用的方法来进行访问(例如HTTP GET),并且对其他资源使用一致的方法来进行访问。

一个开发者一旦对你的API熟悉了之后,他将能通过类似的方法来获取其他的(对于其他资源的)API。

客户端-服务器模式

这意味着客户端应用和服务端应用必需没有任何依赖,并且可以单独发展。客户端仅需要知道资源的URI即可。现如今,这已经是网站开发中的一个常规做法,所以对于你开发的那一边(指客户端或服务端)来说并不需要什么花里胡哨的设计,让它简单即可。

服务端和客户端均可以被换掉并且可以独立开发,只要两者之间的接口保持相同即可。

无状态

Roy fielding从HTTP中得到灵感,所以使其反映在这个约束中。让所有的客户端服务器的交互都变得无状态。服务器不存储任何有关上次客户端发起的HTTP请求的信息。它将每一次的请求都当做一个新请求来看。不使用session,不使用历史记录。

如果客户端需要对终端用户成为一个有状态的应用,例如当用户登录后并且此后作出任何其他的授权动作,那么就应当让客户端在发往服务端的请求中包含所有必要的信息,包括权限及授权信息。

没有任何的客户端上下文应当被存储在服务器中,客户端负责管理程序的状态。

译者注:

有关无状态授权的相关实现可参考JWT(Json Web Token)或者OAuth2协议相关实现

可缓存

在当今世界,对于数据和请求的缓存在任何适用或可行的场景下都是至关重要的。你现在阅读的这个网页同样是一份缓存过的HTML页面版本。对于客户端来说,缓存可以带来性能上的提升,对于服务端来说,由于负载减小,缓存可以增加服务端的可扩展性。

在REST标准中,当缓存可用并且资源声明自己为可缓存时,缓存同样适用于资源,缓存既可以在服务端实现也可以在客户端实现。

良好管理的缓存可以部分或完全地消除掉一些客户端服务器之间的交互,还可以提升系统的可扩展性和性能。

译者注:

此处的API服务端缓存主要针对那种改变非常小或者基本不会发生改变的API响应做出缓存。例如,现在有一个API用来获取某一个年份的法定节假日,例如对2018年的法定节假日,我国(指中国)法定节假日是固定的,而且就那么几天,我们可以处理好后将其缓存,再次请求这个API时,我们即可读取其中的数据。

分层系统

REST允许你使用分层系统体系结构,例如你在服务器A部署API,在服务器B存储数据,在服务器C进行鉴权请求。一个客户端通常无法直接判断它是直接连接到了最终的服务器还是某一个中间人。

按需编码(非必需)

这个选项是非必需的。在大多数时候,你发送的都是打包为Json或XML格式的静态资源表现层数据。但是当你需要的时候,你可以返回可执行的代码来支持你的客户端部分功能的运作,例如客户端通过你的API来请求一段用来获得UI宽度的代码,这是允许的。

译者注:

客户端向服务端请求代码,多半是JavaScript这种的用来做UI或实现部分业务逻辑功能的代码。

所有上述的约束可以帮助你建立一个真正的RESTful API,而且你应当遵守他们。当然,在某些时刻,你也可能会违反其中的一两个约束。不过不用担心,你仍然在制作一个RESTful API,但是不是“真正的RESTful API”

注意:所有上述的约束都与WWW(web)紧紧关联在一块。使用RESTful API,你可以用你的web服务做与web页面相同的事情。