代码之家  ›  专栏  ›  技术社区  ›  Rich Apodaca

那个RESTAPI真的是RPC吗?罗伊·菲尔丁似乎这么认为

  •  92
  • Rich Apodaca  · 技术社区  · 16 年前

    很多我认为我知道的关于休息的事情显然是错误的——我并不孤单。这个问题有很长的引入时间,但似乎是必要的,因为信息有点分散。如果你已经熟悉这个话题,那么实际的问题就在最后。

    从罗伊·菲尔丁的第一段 REST APIs must be hypertext-driven 很明显,他认为他的作品被广泛误解了:

    很多人将任何基于HTTP的接口称为RESTAPI,这让我很沮丧。今天的例子是 SocialSite REST API . 这就是RPC。它叫RPC。显示器上的耦合太多了,应该给它一个X等级。

    Fielding继续列出RESTAPI的几个属性。其中一些似乎与SO和其他论坛上的共同实践和共同建议背道而驰。例如:

    • 除了初始的URI(书签)和一组适用于预期访问群体的标准化媒体类型(即任何可能使用该API的客户机都应该理解)之外,不应在事先知情的情况下输入REST API。……

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

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

    “超文本”的概念起着核心作用——远比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访问关联资源和父资源,或者在创建/删除资源后采取行动。

    整个系统的关键是,响应由包含在媒体类型中的超文本组成,该媒体类型本身将向代理程序发送继续进行的选项。这和浏览器为人类工作的方式没什么不同。

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

    菲尔丁发布了 follow-up 在这篇文章中,他回应了批评,认为他的讨论过于抽象,缺乏实例,行话丰富:

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

    因此,对于其他的专家来说,有两个简单的问题是:如何解释Fielding所说的内容,以及在记录/实现RESTAPI时如何将其付诸实践?

    编辑:这个问题是一个例子,说明如果你对你所说的没有名字,学习一些东西是多么困难。本例中的名称是“作为应用程序状态引擎的超媒体”(hateoas)。

    9 回复  |  直到 10 年前
        1
  •  19
  •   SerialSeb    16 年前

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

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

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

        2
  •  8
  •   Darrel Miller    16 年前

    我觉得你的解释是正确的。我相信菲尔丁的约束条件可以实际应用。

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

        3
  •  5
  •   jeremyh    14 年前

    我一直在寻找一个遵循hateoas编写的API的好例子,并且很难找到一个(我发现SuncloudAPI和Atompub都很难应用于“正常”的API情况)。所以我尝试在我的博客上做一个现实的例子,遵循罗伊·菲尔丁的建议,这意味着一个适当的REST实现。我发现很难想出这个例子,尽管它在原则上相当简单(只是在使用API而不是网页时会混淆)。我理解罗伊的观点并同意,这只是一种心态上的转变,即要正确地为API实现。

    看一看: API Example using Rest

        4
  •  4
  •   aehlke    16 年前

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

    关于休息和相关仇恨的一些好讨论:

    Advantages Of (Also) Using HATEOAS In RESTFul APIs

    How to GET a cup of coffee

        5
  •  4
  •   Rich Apodaca    16 年前

    对于那些感兴趣的人,我在实践中发现了一个关于hateoas的详细例子。 Sun Cloud API .

        6
  •  4
  •   redben    16 年前

    大多数人都会出错的是(至少我认为)在其他世界,你没有记录你的“REST接口”,你记录的是一种媒体类型,独立于你的服务器或服务。

        7
  •  1
  •   Keith Gaughan    16 年前

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

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

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

    我们还包括非规范性(信息性)文档,该文档附带了一个免责声明,即不要对文档中提到的URI进行过多的阅读,该声明给出了典型的客户机-服务器交互示例。这就把相当抽象的规范性文件具体化了。

        8
  •  1
  •   Sampada    10 年前

    我认为,在过去的几年中,技术人员已经开始接受资源的概念,以及什么是真正的或不是休息的。

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

    级别0是当您有一个入口点URI时,就像SOAP。

    级别1意味着API能够区分不同的资源,并且有多个入口点——仍然有肥皂味。

    级别2主要是使用http动词-get、post、delete。这就是休息真正进入画面的层次。

    在第3级,您开始使用超媒体控件来创建API 真正地 宁静的

    建议的进一步阅读链接:

        9
  •  0
  •   redzedi    14 年前

    让我们假设 GET /foos/createForm 调用以获取窗体字段值,当我们要创建 POST /foos . 现在应该在响应中提到这个特定的URL,即用于创建foos的1。 获取/foos/createform 作为根据菲尔丁的提议提交行动链接,对吗?
    那么,将动作映射到众所周知的HTTP动词到动作的好处是什么,“代码/配置上的约定”的事情是无效的。

    推荐文章