“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
在当前的文献中,REST 通常被宣传为自切片面包以来最好的东西。然而,它伴随着许多挑战。Martin Fowler 写了一篇关于REST 荣耀的文章。他列出了使 API 成为真正的REST 的三个步骤:
在每个步骤中,问题都潜伏着。这篇博文重点列出了其中的一些问题并提供了解决方法的提示。
资源
REST 从 SOAP 的缺点中脱颖而出。SOAP 提供单个端点并根据有效负载执行代码。REST 的思想是提供多个端点,每个端点执行不同的代码。
老实说:现阶段几乎没有什么问题。最大的一个涉及从现有身份猜测一个身份。如果资源 ID 是连续的甚至只是数字,则很容易猜测其他资源的端点,例如,从/customers/1
到/customers/2
。解决方案是使用非连续的非数字 id,即通用唯一标识符。
让我们走上 REST 成熟度模型。
HTTP 动词
HTTP 动词是迈向 REST 荣耀的下一步。它们来自“过去”与 HTML 的交互。交互来自CRUD操作。
这很简单:
手术 | 动词 | ||
创建 | POST |
||
读 | GET |
||
更新 | PUT |
PATCH |
|
删除 | DELETE |
API 的主要问题是您需要超越 CRUD。让我们想象一个银行转账的具体例子:它从一个账户中取款并将其转移到另一个账户。我们应该如何建模呢?
我们可以使用原始帐户作为资源,例如 。 , /accounts/a1b2c3d4e5f6
. 目标账户、金额等可以作为查询参数或在正文中传递。但是我们应该使用什么 HTTP 动词呢?
它确实改变了已识别的资源,但它有“副作用”。它还更改了另一个资源:目标帐户。以下是关于如何管理 HTTP 谓词的几个选项:
- 使用
POST
,因为它会更改源资源。它具有误导性,因为它没有说明副作用。 - 使用专用的 HTTP 动词,例如
TRANSFER
. 它不是不言自明的,并且与 REST 原则相反。 POST
与所谓的自定义方法一起使用。自定义方法是 Google API 改进建议:
自定义方法只能用于无法通过标准方法轻松表达的功能;如果可能,更喜欢标准方法,因为它们具有一致的语义。
HTTP URI必须使用一个
:
字符后跟自定义动词。
- 这是我们的银行账户转账 URI
/accounts/a1b2c3d4e5f6:transfer
:。
最好的选择是什么?“这取决于。”
超媒体
Fowler 将超媒体控件描述为实现 REST 荣耀的最终步骤。它现在被称为HATEOAS:
使用 HATEOAS,客户端与网络应用程序交互,其应用程序服务器通过超媒体动态提供信息。除了对超媒体的一般理解之外,REST 客户端几乎不需要了解如何与应用程序或服务器交互。
HATEOAS 是一个概念。这是从维基百科获取的可能实现。当一个人请求一个银行账户时,例如/accounts/a1b2c3d4e5f6
,响应包含指向对该特定银行账户可能采取的行动的链接:
如果余额为负数,则只有存款链接可用:
REST 的一个常见问题是缺乏标准。HATEOAS 也不例外。实现某种程度标准化的第一个尝试是JSON 超文本应用程序语言,又名 HAL。请注意,它是在 2012 年开始的:最新版本是 2016 年的,目前仍处于草案阶段。
这是一个总结提案的快速图表:
- 可用链接
- 链接到自己
- 告诉可以使用哪个 HTTP 动词
- 存款链接
标准化的另一种尝试是RFC 8288,又名 Web 链接。它描述了格式并包含一个链接关系注册表,例如,alternate
和copyright
。与 HAL 最显着的区别是 RFC 8288 通过 HTTP 响应标头传达链接。
- 链接到具有非标准
self
关系类型的当前资源 - 使用扩展
https://my.bank/deposit
关系类型和任意title
目标属性存放链接
其他替代媒体类型规范可用。
名称 | 描述 | 由...提供 |
交换陈述的统一基础 | UBER 文档格式是一种最小的读/写超媒体类型,旨在支持简单的状态传输和基于临时超媒体的转换。该规范描述了该格式的 XML 和 JSON 变体,并提供了支持通过 HTTP 协议进行 UBER 编码消息的指南。 | 个人 |
集合+JSON | Collection+JSON 是一种基于 JSON 的读写超媒体类型,旨在支持简单集合的管理和查询。 | 个人 |
JSON:API | JSON:API 是关于客户端应如何请求获取或修改资源以及服务器应如何响应这些请求的规范。 JSON:API 可以通过扩展和配置文件轻松扩展。 | 个人 |
警笛 | Siren 是一种用于表示实体的超媒体规范。由于 HTML 用于直观地表示网站上的文档,因此 Siren 是一种通过 Web API 呈现实体的规范。Siren 提供结构来传达有关实体的信息、执行状态转换的操作以及客户端导航的链接。 | 个人 |
应用程序级配置文件语义 | ALPS 文档可以用作配置文件来解释具有与应用程序无关的媒体类型(例如 HTML、HAL、Collection+JSON、Siren 等)的文档的应用程序语义。这增加了跨媒体类型的配置文件文档的可重用性。 | IETF |
奖励:HTTP 响应状态
Fowler 的帖子没有提到的是 HTTP 响应状态。大多数读者都熟悉状态范围:
- 信息响应:100 – 199
- 成功回复:200 – 299
- 重定向消息:300 – 399
- 客户端错误响应:400 – 499
- 服务器错误响应:500 – 599
同样,大多数也具有定期发现的 HTTP 状态:
问题在于,除了这些简单的案例之外,它还是一团糟。例如,看看这个StackOverflow 问题:“哪个 HTTP 状态代码表示尚未准备好,稍后再试?” 以下是建议答案的摘要,从最高票数到最低票数:
- 503服务不可用
- 202 Accepted(接受的答案)
- 423 锁定
- 404 未找到
- 302 找到
- 409 冲突
- 501 未实施(否决)
这不是一个直截了当的答案:围绕替代方案存在很多争论。作为记录,我认为接受的答案是正确的。
这在设计者方面已经很多了,但客户端也包含很多不确定性,因为一些大型 API 提供商使用他们自己的 HTTP 状态代码。
结论
“REST 的荣耀”意义不大。尽管有任何相反的说法,但没有可依赖的单一语义。事实上,它主要取决于实现和解释:两者都需要记录自定义行为而不是依赖共享规范。
SOAP 最大的缺陷是它的复杂性和它对大公司的关注,但它至少提供了一套共享的标准规范。业界用 REST 取代了它:不是规范,而是架构站点。REST 更简单,因此更容易上手,但它需要大量定制工作,这因项目而异。
有提供一些标准化的倡议,但它们很少,而且有些与其他的不一致。而且,他们的吸引力很低,所以人们不知道他们,这就造成了恶性循环。我几乎不提倡回到 SOAP,尽管我有时确实会怀念它。