那个REST API真的是RPC吗?罗伊菲尔丁似乎在想

时间:2009-07-22 09:41:21

标签: rest hateoas

我认为我对REST的大量了解显然是错误的 - 而且我并不孤单。这个问题有很长的引导时间,但似乎是必要的,因为信息有点分散。如果你已经熟悉这个话题,最后会出现实际问题。

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

  

我对使用REST API调用任何基于HTTP的界面的人数感到沮丧。今天的例子是SocialSite REST API。那就是RPC。它尖叫RPC。显示器上有很多耦合,应该给它一个X等级。

Fielding继续列出REST API的几个属性。他们中的一些人似乎反对SO和其他论坛的常见做法和共同建议。例如:

  • 应输入REST API,除了初始URI(书签)和适用于目标受众的标准化媒体类型集之外没有任何先验知识(即,任何可能使用API)。 ...

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

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

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

  

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

     

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

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

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

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

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

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

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

菲尔丁发布了一个follow-up,他批评他的讨论过于抽象,缺乏例子和行话丰富:

  

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

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

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

9 个答案:

答案 0 :(得分:19)

我认为你的解释主要涵盖它。 URI是不透明的标识符,在大多数情况下,应该不会超出用户代理用来访问应用程序的书签URI。

至于记录,这个问题已经完成了很多次。您可以记录媒体类型及其包含的超链接控件(链接和表单),以及您希望的交互模型(请参阅AtomPub)。

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

答案 1 :(得分:8)

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

我真的希望看到有人发布一些如何记录REST接口的好例子。有很多不好的例子,有一些有用的例子可以指出用户非常有价值。

答案 2 :(得分:5)

我一直在寻找一个在HATEOAS之后编写的API的一个很好的例子,但是找不到它(我发现SunCloud API和AtomPub的东西很难应用于“正常”的API情况)。所以我尝试在我的博客上做一个真实的例子,跟随Roy Fieldings关于成为一个合适的REST实现意味着什么的建议。我发现很难提出这个例子,尽管它原则上相当简单(只是在使用API​​而不是网页时会感到困惑)。我得到了Roy提出的问题并同意,这只是为了正确实现API的思维方式的转变。

看看:API Example using Rest

答案 3 :(得分:4)

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

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

Advantages Of (Also) Using HATEOAS In RESTFul APIs

How to GET a cup of coffee

答案 4 :(得分:4)

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

答案 5 :(得分:4)

大多数人出错的地方是(至少我认为)在REST世界中你没有记录你的“Rest界面”,你所记录的是媒体类型,与你的服务器或服务无关。

答案 6 :(得分:1)

绝对正确。我还要注意,只要模式来自服务器接收的文档(OpenSearch是一个合适的例子),URI模板在RESTful应用程序中就完全没问题了。对于URI模板,您可以记录它们的使用位置以及模板中预期的占位符,而不是模板本身。与Wahnfrieden所说的略有不同,这不是例外。

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

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

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

答案 7 :(得分:1)

我认为现在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。

建议的进一步阅读链接:

答案 8 :(得分:0)

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