REST架构风格与RESTFUL API设计最佳实践

什么是架构风格

架构风格,最初是来源于建筑学的一个名词。比如你看到苏州园林,有假山,有亭台,有人工河,有直廊,你就能很容易分辨这是一种园林风格的建筑,看到房子里大都是木制,并且有榻榻米,你也能很确定这是日式风格家居。所以,像假台,亭台,木制地板,榻榻米,这些都是风格特征。这些东西都是某一种风格形式所具有的特定约束条件。有了它们,你才能合理地区分建筑风格。同样,在软件领域,架构风格与建筑风格非常类似。在fielding博士的论文中,架构风格的定义为:架构风格是一组相互协作的架构约束,这些架构约束限制了架构元素的角色和功能,以及在任何一个遵循该架构风格的架构中允许存在的元素之间的关系。

什么是REST?

REST全称Representational State Transfer,翻译成中文即是:表述性状态转移。我在第一次接触该词时,也是万千疑惑,这到底是谁翻译的鬼东西?其实,REST是Roy Fielding博士于2000年在他的博士论文里提出的一种web架构风格。

简单来说,REST是定义了一组架构约束原则,并能应用于分布式web应用的一种架构风格。

REST的六个架构约束

客户端-服务器

无状态

缓存

统一接口

分层系统

按需代码

REST的六个架构约束同时也是REST架构风格的推导过程。接下来,我们来一个个细说这些约束原则。

客户端-服务器

REST引入客户端-服务器这一约束的目的是为了更好的分离用户界面与数据存储这两个关注点,此约束的优点是:改善了用户界面跨平台的可能性,即提高了客户端程序的可移植性。同时简化服务器组件,改善了系统的可伸缩性。最重要的一点,这种分离使得组件可独立进化,从而支持多个组织领域的互联网规则的需求。

无状态

无状态这一约束,即通信过程本质上应该是无状态的。即客户端向服务端发起的每个请求都必须包含足够信息来使客户端准确地表达请求含义,同时客户端不能利用储存在服务器端的任何上下文,会话状态必须全部保存在客户端。举个简单的例子,你正在浏览此文,服务端并不关心你是谁,只关心请求是否能有权限查看此文而已。你有权限,我则给你展示,你没有,则不展示。至于你有没有登录,服务端针对此次的请求是不关心。

缓存

引入缓存这一约束,是为了解决网络天然的传输效率这一症结,当有大量并发网络请求,缓存是解决服务端压力的一大利器。

统一接口

统一接口约束是REST最核心,也是区别于其它架构风格的一个最重要特征。它强调组件与组件之间,必须有统一的接口。同时REST提出了四个接口约束条件:资源的识别(identification of resources)、通过表述来操作资源(manipulation of resources through representations)、自描述的消息(self-descriptive messages)、以及作为应用状态引擎的超媒体(hypermedia as the engine of application state,即HATEOAS)。这些约束条件,将在后文所说的RESTful API中详细提到。

分层系统

引入分层系统这一约束,是为了解决分布式网络应用中量的问题,一般而言,单体软件是非常庞大且效率低下,为此,很多软件先驱总结了一系列方法,这其中就包括分层的思想,通过垂直或者水平的划分应用,将网络流量交给分布式网络中不同的,但功能类似或者相同的组件去处理。这就让系统在业务上很好的解耦,有利于实践中的软件维护。

按需代码

按需代码的意思是,REST允许客户端通过下载并执行一些来自于服务端的脚本程序,来对客户端功能进行扩展。这样可以简化客户端功能的开发,比如常见的移动端webview,web小游戏等。所以按需代码改善了客户端及系统的可扩展性。同时也降低了可见性,因此它只是REST架构中的一个可选约束。

推导小结

本文没有详细讲解什么是架构约束,什么是架构属性等知识,这些东西如果有兴趣了解,都可以去拜读一下fielding博士的论文。REST架构风格由一组经过选择的架构约束组成。通过这些架构约束在候选架构上产生所期待的架构属性。尽管能够独立考虑其中的每个架构约束,但是根据它们在公共架构风格中的来源对它们进行描述,使得我们理解选择它们背后的基础理论更加容易。

如何向客户端呈现你的数据

在Roy Fielding的论文中提到,架构师在向用户呈现数据的方式上,一般有如下三种选择:

在数据源(服务端)对数据进行呈现,并向客户端发送一个固定格式的镜像(html,image,text)。

将数据及呈现引擎封装,并将两者一直发送给用户(html+js等可执行脚本)。

发送原始数据及一些描述数据的元信息(http报文中的content-type及body部分)。

第一种类似于我们所看到的静态页面,就是我们常说的渲染在服务端完成,也是前后端未分离时的做法,这种做法的好处是简化了客户端的实现,缺点是增加了服务端的负担及限制了客户端对数据的可呈现能力。第二种是在第一种的基础上,增加了客户端的可呈现能力。此时仍然未前后端分离,但服务端会给出一些驱动数据的呈现引擎(例如js脚本等),这样数据有了更多的表现力。但它的呈现还是受限于呈现引擎(js脚本)。同时也增大了数据的传输量。第三种类似于现在常见的HTTP API,前后端已分离。比如用户通过一个API,可以获取到一些json结构的数据,客户端根据数据按照自己的呈现方式进行渲染。这种方式的好处不言而喻,服务端减轻了自己的工作,客户端增加了可伸缩性。但此种方式的前提是,双方需要理解相同的数据类型(content-type)。

REST的数据元素

REST综合上以上三种方式。提出以表述(Representation)及表述的呈现引擎来向客户端发送标准的数据格式。REST因此获得了客户端-服务器风格的分离关注点的好处,而且不存在服务器的可伸缩性问题。REST的数据元素由以下部分组成:

关于REST的介绍就等这里,详细信息请参考Roy fielding博士的论文 Architectural Styles andthe Design of Network-based Software Architectures 第五章。

什么是RESTful API?

REST一般应用于HTTP协议,实际上,HTTP/1.1就是基于REST架构的,REST的高度抽象其实是一个有限自动机。显然,超媒体是REST的驱动引擎,这一点正是HTTP的特性。所以HTTP甚至整个web,都可以说是一个有限自动机。

一般,我们认为只要符合REST风格的API,都是RESTful API。同时,RESTful API就是最大限度的利用了http能力的API。

RESTful API最佳实践

1. 使用名词而非动词

例如我们在获取一个用户资源时,尽量语义化,最好使用形如:

而不是:

因为在HTTP协议中,已经有method(GET,POST,PUT,DELETE)来指明动作,而URL只是资源的唯一标识而已。

由于大部分国人英文水平的问题,不建议在资源名中使用复数

2. 使用HTTP Method代替资源操作

示例:

3. 使用HTTP STATUS CODE + 自定义错误码

HTTP状态码是HTTP规范预定义的一组HTTP响应状态标识。从1xx - 5xx已经明确返回值。很多情况下,一些程序员在开发过程中,不管是正确还是正确情况下,都返回200的状态码,然后用自定义的错误码来标识错误信息。这虽然对开发没有问题,但已经弱化了HTTP本身的能力,以及一些开发框架及代理服务器的能力。例如很多框架本身就封装了对HTTP状态码异常的处理流程。

常见的HTTP状态有如下:

4. 使用API版本

目前前后端分离的情况下,客户端更新出去后,用户实际上是很难与企业产品最新版本保持一致,所以服务端也需要支持不同版本的API,这样就算用户在使用老版本的客户端,也能正常使用产品业务。

示例:

5. 使用通用的查询参数名

客户端在与服务端对接时,经常会有一些列表查询接口,使用分页,条件过滤等。对于这些参数,双方尽量约定通用的参数名。以便双方开发通用的接口。

6. 返回通用的结构体

服务端应保持API的返回结构体一致,这样客户端无须针对每个接口做特殊处理,有利于双方开发效率提高。

示例:

约定默认返回JSON格式,并且只含有data,msg,url,code四个属性:

总结

本文所述的RESTful API,仅为Richardson成熟度模型中第二级API,真正的RESTful API应该是HATEOAS的,即以超媒体作为应用状态的引擎(Hypermedia as the Engine of Application State),这种API目前在实践中应用的比较少,也没有比较成熟的方案。所以暂不介绍

Richardson成熟度模型:

REST是一种看似简单,其实有很大学问的架构风格,RESTful API也是时下最流行的API风格。RESTful的设计只要符合REST约束,大部分情况下也是可行的。所以实践中只要有统一的规范风格更重要。同时,使用一种风格的API,有利于思考模式,工作模式的转变。这对想做架构师的程序员是非常有益的。例如使用json-RPC风格的API,那么思维必定走向RPC。RPC这种耦合性高,依赖于库的API,大家使用过程务必要非常小心。

参考文献

[1]Architectural Styles and the Design of Network-based Software Architectures

[2]10 Best Practices for Better RESTful API

[3]RESTful API Designing guidelines — The best practices

本文原创自PHP技术大全QQ群的js同学之手。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180223A0LIHH00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券