100

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

从 Roy Fielding 的REST APIs must be hypertext-driven的第一段开始,很明显他认为他的工作被广泛误解了:

我对将任何基于 HTTP 的接口称为 REST API 的人数感到沮丧。今天的例子是SocialSite REST API。那就是RPC。它尖叫 RPC。展示的耦合太多了,应该给它一个 X 评级。

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

  • 除了初始 URI(书签)和适合目标受众(即,任何可能使用 API 的客户端都可以理解)的标准化媒体类型集之外,应该在没有任何先验知识的情况下输入 REST API。...

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

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

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

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

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

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

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

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

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

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

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

菲尔丁发表了一篇后续文章,回应批评称他的讨论过于抽象、缺乏示例且行话丰富:

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

因此,对于 REST 专家来说,有两个简单的问题,有实用的思维方式:您如何解释 Fielding 所说的内容,以及在记录/实施 REST API 时如何将其付诸实践?

编辑:这个问题是一个例子,说明如果你没有为你所谈论的内容命名,那么学习一些东西会有多么困难。在这种情况下,名称是“作为应用程序状态引擎的超媒体”(HATEOAS)。

4

9 回答 9

22

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

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

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

于 2009-07-22T12:57:30.060 回答
8

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

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

于 2009-07-22T17:11:53.917 回答
5

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

看看:使用 Rest 的 API 示例

于 2012-05-16T18:58:36.847 回答
4

提供有关如何构建 URI 的指令的一个例外是允许在超文本响应中发送 URI 模板,其中的字段由客户端自动替换,使用超文本中的其他字段。这通常不会最终节省很多带宽,因为 gzip 压缩会很好地处理 URI 的重复部分,而不必为此烦恼。

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

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

如何得到一杯咖啡

于 2009-07-22T14:09:43.017 回答
4

对于那些感兴趣的人,我在Sun Cloud API中找到了 HATEOAS 实践的详细示例。

于 2009-07-26T19:31:44.707 回答
4

大多数人弄错的事情是(至少我认为)在 REST 世界中,您没有记录您的“Rest 接口”,您记录的是一种媒体类型,与您的服务器或服务无关。

于 2010-06-12T10:15:55.817 回答
4

我认为,在 REST 出现的这些年里,技术人员已经接受了资源的概念以及什么是真正的 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真正成为RESTful。

进一步阅读的建议链接:

于 2016-06-01T10:58:26.483 回答
1

完全正确。另外我要注意的是,只要模式来自从服务器接收到的文档(OpenSearch 是一个合适的例子),URI 模板在 RESTful 应用程序中非常好。对于 URI 模板,您需要记录它们的使用位置以及模板中预期的占位符是什么,而不是模板本身。与 Wahnfrieden 所说的略有不同,这并非个例。

例如,在我的工作中,我们有一个内部域管理系统,并且服务文档指定了两个 URI 模板:一个用于为域资源生成最佳猜测 URI,另一个用于构造一个用于查询域可用性的 URI。仍然可以翻阅域集合以找出给定域的 URI 是什么,但鉴于它管理的域数量巨大,这对客户端来说是不可行的,所以给他们一种猜测是什么的方法从客户端的角度来看,域资源的 URI 在易于实现方面可能是一个巨大的胜利,从服务器的角度来看,它的带宽可能是巨大的。

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

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

于 2009-07-22T14:45:30.853 回答
0

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

于 2012-06-18T11:10:19.280 回答