那个 REST API 真的是 RPC 吗? Roy Fielding 似乎是这么认为的

我认为我所知道的关于 REST 的大部分东西显然是错误的——我并不是唯一一个这样认为的人。这个问题有一个很长的导入,但它似乎是必要的,因为信息有点分散。如果您已经熟悉这个主题,那么实际的问题将出现在最后。

从罗伊•菲尔丁(Roy Fielding) REST API 必须是超文本驱动的的第一段来看,很明显他认为自己的作品被广泛误解了:

许多人将任何基于 HTTP 的接口称为 REST API,这让我感到沮丧。今天的例子是 SocialSite REST API。那是 RPC。看起来像 RPC。有这么多的耦合显示,它应该给予一个 X 评级。

Fielding 接着列出了 RESTAPI 的几个属性。其中一些建议似乎违背了社会保障组织和其他论坛的共同做法和共同建议。例如:

  • 除了初始 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 的 URI,例如,针对/fos 发出 GET 请求。(这些 URI 可能会遵循上面的模式,但这不是重点。)答复使用的媒体类型能够传达如何访问每个项目以及可以用它来做什么,从而产生了上面的第三点。因此,API 文档应该重点解释如何解释响应中包含的超文本。

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

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

但这只是我此时此刻最好的猜测。

菲尔丁发表了一篇 跟进文章,回应了一些批评,认为他的讨论过于抽象,缺乏实例,术语丰富:

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

因此,有两个简单的问题要问那些具有实用思维的 REST 专家: 如何解释 Fielding 所说的内容,以及在编写/实现 REST API 时如何将其付诸实践?

编辑: 这个问题是一个例子,说明如果你没有一个名字来表示你所谈论的内容,那么学习一样东西是多么的困难。本例中的名称是“ Hypermedia as The Engine of Application State”(HATEOAS)。

15380 次浏览

I think your explanation mostly covers it. URIs are opaque identifiers that should, for the most part, not be communicated beyond the bookmark URI that is used by the user agent to access the app.

As for documenting, this question has been done quite a few times. You document your media type, together with the hyperlink controls that it contains (links and forms), and the interaction model if you so wish (see AtomPub).

If you document the URIs or how to build them, you're doing it wrong.

The one exception to giving instruction on how to build URIs is that it is permissible to send a URI template in the hypertext response, with fields to be substituted automatically by the client, using other fields in the hypertext. This doesn't usually end up saving much bandwidth though since gzip compression will handle the repeated parts of URIs well enough to not bother with this.

Some good discussions on REST and the related HATEOAS:

Advantages Of (Also) Using HATEOAS In RESTFul APIs

How to GET a cup of coffee

Absolutely correct. I'd note in addition that that URI templates are perfectly fine within a RESTful application so long as the patterns are from documents received from the server (OpenSearch being a suitable example). For URI templates, you document where they're being used and what the expected placeholders in the template are, but not the templates themselves. Slightly contrary to what Wahnfrieden said, this isn't an exception.

For example, at my work we have a internal domain management system, and the service document specifies two URI templates: one for producing a best guess URI for a domain resource, and another for constructing a URI for querying domain availability. It's still possible to page through the domains collection to figure out what the URI of a given domain is, but given the immense number of domains it manages, this wouldn't be feasible for the client, so giving them a way to guess what the URI of a domain resource might be is a huge win in terms of ease of implementation from the client's perspective, and bandwidth from the server's.

On to your question: Our normative documentation is exposed resources, the effect of various methods on those resources, and the representation media types used and their schemas, and what kind of resources the URIs in those representions point to.

We also include non-normative (informative) documentation that has attached to it a disclaimer not to read too much into the URIs mentioned in the document, which gives examples of typical client-server interactions. This puts the rather abstract normative documentation in concrete terms.

Your interpretation seems correct to me. I do believe that Fielding's constraints can be practically applied.

I really would like to see someone publish some good examples of how to document a REST interface. There are so many poor examples, have some valid ones to point users to would be very valuable.

For those interested, I found a detailed example of HATEOAS in practice in the Sun Cloud API.

The thing that most people get wrong is that (at least i think) in the REST world you don't document your "Rest interface", what you document is a media type, independently of your server or service.

I have been looking for a good example of an API written following the HATEOAS and had trouble finding one (I found both the SunCloud API and AtomPub stuff difficult to apply to a "normal" API situation). So I tried making a realistic example on my blog that followed Roy Fieldings advice on what it means to be a proper REST implementation. I found it very difficult to come up with the example, despite the fact that it is fairly simple in principle (just confusing when working with an API as opposed to a webpage). I get what Roy was taking issue with and agree, it is just a shift in mindset to implement properly for an API.

Have a look: API Example using Rest

Let's assume GET /foos/createForm is invoked to get form fields values for which must be provided when we go to create POST /foos . Now this particular URL i.e the 1 used to create foos should be mentioned within the response for GET /foos/createForm as a submit action link according to Fielding's proposition, right ?
Then what is the benefit of mapping actions to well-known Http verbs to actions, "convention over code/config" thing is nullified.

I think over the number of years that REST has been out there now, technologists have come to terms with the concept of a Resource and what really is or isn't RESTful.

According to the Richardson Maturity Model, there are 4 levels (0-3) that define how RESTful your API is, with 3 meaning a truly RESTful API, just as Roy Fielding intended it to be.

Level 0 is when you have one entry point URI - like SOAP.

Level 1 means the API is able to distinguish between different resources, and has more than one entry points - still smells of SOAP.

Level 2 is when you use HTTP verbs - GET, POST, DELETE primarily. This is the level at which REST really comes into picture.

At Level 3, you start using hypermedia controls to make your API truly RESTful.

Suggested links for further reading: