我认为自己对 REST 的了解显然是错误的——而且我并不孤单。这个问题的引入时间较长,但似乎有必要,因为信息有点分散。如果您已经熟悉这个主题,那么实际的问题将在最后出现。

摘自罗伊·菲尔丁的第一段 REST API 必须是超文本驱动的, ,很明显他认为他的作品被广泛误解:

我对将任何基于 HTTP 的接口称为 REST API 的人数感到沮丧。今天的例子是 社交网站 REST API. 。那就是RPC。它尖叫着 RPC。显示的耦合太多,应该给予 X 评级。

Fielding 接下来列出了 REST API 的几个属性。其中一些似乎违背了 SO 和其他论坛上的常见做法和常见建议。例如:

  • 输入 REST API 时,除了初始 URI(书签)和适合目标受众的标准化媒体类型集(即,预期可能被任何可能使用该 API 的客户端理解)之外,无需任何先验知识。...

  • REST API 不得定义固定的资源名称或层次结构(客户端和服务器的明显耦合)。...

  • REST API 应该花费几乎所有的描述性工作来定义用于表示资源和驱动应用程序状态的媒体类型,或者为现有标准媒体类型定义扩展关系名称和/或支持超文本的标记。...

“超文本”的概念起着核心作用 - 比 URI 结构或 HTTP 动词的含义更重要。“超文本”在评论之一中定义:

当我[菲尔丁]说超文本时,我指的是信息和控件的同时呈现,使得信息成为用户(或自动机)获得选择和选择操作的可供性。超媒体只是文本含义的扩展,将时间锚点包含在媒体流中;大多数研究人员已经放弃了这种区别。

超文本在浏览器上不必是 HTML。当机器理解数据格式和关系类型时,它们可以跟踪链接。

我猜测是在这一点上,但上面的前两点似乎表明 Foo 资源的 API 文档如下所示,导致客户端和服务器之间的紧密耦合,并且在 RESTful 系统中没有位置。

GET   /foos/{id}  # read a Foo
POST  /foos/{id}  # create a Foo
PUT   /foos/{id}  # update a Foo

相反,代理应该被迫发现所有 Foo 的 URI,例如,通过针对 /foos 发出 GET 请求。(这些 URI 可能会遵循上面的模式,但这不是重点。)响应使用的媒体类型能够传达如何访问每个项目以及可以用它做什么,从而产生了上面的第三点。因此,API 文档应重点解释如何解释响应中包含的超文本。

此外,每次请求 Foo 资源的 URI 时,响应都包含代理发现如何继续操作所需的所有信息,例如,通过 URI 访问关联资源和父资源,或者在创建后采取操作/删除资源。

整个系统的关键是响应由包含在媒体类型中的超文本组成,该媒体类型本身向代理传达继续操作的选项。这与人类浏览器的工作方式没有什么不同。

但这只是我在这个特定时刻的最佳猜测。

菲尔丁发布了 跟进 他在其中回应了批评他的讨论过于抽象、缺乏例子、行话过多的批评:

其他人会尝试以更直接或更适用于当今某些实际问题的方式来解读我所写的内容。我可能不会,因为我太忙于解决下一个主题,准备会议,编写另一个标准,去某个遥远的地方旅行,或者只是做一些让我觉得我已经赚到薪水的小事情。

因此,对于具有实用心态的 REST 专家来说,有两个简单的问题:在记录/实现 REST API 时,您如何解释 Fielding 所说的以及如何将其付诸实践?

编辑:这个问题是一个例子,说明如果你不知道你所谈论的内容的名称,那么学习某些东西是多么困难。本例的名称是“超媒体作为应用程序状态引擎”(HATEOAS)。

有帮助吗?

解决方案

我认为你的解释大部分涵盖了它。URI 是不透明的标识符,在大多数情况下,不应在用户代理用于访问应用程序的书签 URI 之外进行通信。

至于记录,这个问题已经做过好几次了。您可以记录您的媒体类型及其包含的超链接控件(链接和表单)以及交互模型(如果您愿意)(请参阅 AtomPub)。

如果您记录了 URI 或如何构建它们,那么您就做错了。

其他提示

你的解释对我来说似乎是正确的。我确实相信菲尔丁的约束可以实际应用。

我真的很希望看到有人发布一些关于如何记录 REST 接口的好示例。有很多糟糕的例子,有一些有效的例子来指导用户将是非常有价值的。

我一直在寻找一个遵循 HATEOAS 编写的 API 的好示例,但很难找到一个(我发现 SunCloud API 和 AtomPub 的东西都很难应用于“正常”API 情况)。因此,我尝试在我的博客上制作一个实际示例,遵循 Roy Fieldings 关于正确 REST 实现的含义的建议。我发现很难想出这个例子,尽管它在原理上相当简单(只是在使用 API 而不是网页时令人困惑)。我明白 Roy 的异议并同意,这只是正确实施 API 的思维方式的转变。

看一看: 使用 Rest 的 API 示例

给出有关如何构建 URI 的说明的一个例外是,允许在超文本响应中发送 URI 模板,其中字段将由客户端使用超文本中的其他字段自动替换。不过,这通常不会节省太多带宽,因为 gzip 压缩可以很好地处理 URI 的重复部分,无需为此烦恼。

关于 REST 和相关 HATEOAS 的一些很好的讨论:

在 RESTFul API 中(同时)使用 HATEOAS 的优点

如何获得一杯咖啡

对于那些感兴趣的人,我在实践中找到了 HATEOAS 的详细示例 太阳云API.

大多数人犯的错误是(至少我认为)在 REST 世界中,您不会记录您的“Rest 接口”,您记录的是一种媒体类型,独立于您的服务器或服务。

完全正确。另外我还要指出的是,只要模式来自从服务器接收的文档(OpenSearch 就是一个合适的示例),URI 模板在 RESTful 应用程序中就完全没问题。对于 URI 模板,您记录它们的使用位置以及模板中预期的占位符是什么,但不记录模板本身。与 Wahnfrieden 所说的略有相反,这并不是一个例外。

例如,在我的工作中,我们有一个内部域管理系统,服务文档指定了两个 URI 模板:一个用于为域资源生成最佳猜测 URI,另一个用于构建用于查询域可用性的 URI。仍然可以通过域集合进行分页来找出给定域的 URI,但考虑到它管理的域数量巨大,这对于客户端来说是不可行的,因此给他们一种猜测的方法从客户端的角度来看,域资源的 URI 可能在实现的简便性和服务器的带宽方面是一个巨大的胜利。

关于你的问题:我们的规范文档包括公开的资源、各种方法对这些资源的影响、使用的表示媒体类型及其模式,以及这些表示中的 URI 指向什么类型的资源。

我们还包括非规范(信息性)文档,其中附有免责声明,要求不要过多阅读文档中提到的 URI,其中提供了典型客户端-服务器交互的示例。这使得相当抽象的规范性文档变得具体化。

我认为 REST 已经出现这么多年了,技术专家已经接受了资源的概念以及什么是真正的 RESTful,什么不是 RESTful。

根据 Richardson 成熟度模型,有 4 个级别 (0-3) 定义了您的 API 的 RESTful 程度,其中 3 表示真正的 RESTful API,正如 Roy Fielding 所希望的那样。

级别 0 是指您拥有一个入口点 URI(如 SOAP)。

1 级意味着 API 能够区分不同的资源,并且有多个入口点 - 仍然带有 SOAP 的味道。

级别 2 是指您主要使用 HTTP 动词 - GET、POST、DELETE。这是 REST 真正发挥作用的级别。

在第 3 级,您开始使用超媒体控件来制作您的 API 确实 安宁。

建议进一步阅读的链接:

我们假设 GET /foos/createForm 调用以获取表单字段值,当我们创建时必须提供该值 POST /foos 。现在这个特定的 URL,即用于创建 foos 的 1 应该在响应中提及 GET /foos/createForm 根据菲尔丁的提议作为提交操作链接,对吧?
那么将动作映射到众所周知的 Http 动词到动作有什么好处,“约定优于代码/配置”的事情就失效了。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top