为什么小的固定词汇表被视为RESTful服务的优势?


13

因此,RESTful服务的词汇表中有一组固定的动词。RESTful Web服务从HTTP方法获取这些信息。定义固定的词汇表具有一些假定的优势,但是我并不十分了解这一点。也许有人可以解释。

为什么REST概述的固定词汇表比为每个状态动态定义词汇表更好?例如,面向对象的编程是一种流行的范例。RPC是用来定义固定接口的,但是我不知道为什么人们会认为RPC受这些限制的限制。我们可以动态指定接口,就像RESTful服务动态描述其内容结构一样。

REST被认为是有利的,因为它可以在不扩展词汇量的情况下增长。RESTful服务通过添加更多资源而动态增长。通过动态指定每个对象的词汇表来扩展服务有什么问题?我们为什么不只使用在对象上定义的方法作为词汇,而让我们的服务向客户描述这些方法是什么以及它们是否有副作用?

从本质上讲,我感觉到服务器端资源结构的描述等同于词汇表的定义,但是随后我们被迫使用有限的词汇表来与这些资源进行交互。

固定的词汇量真的能使客户端的关注与服务器的关注脱钩吗?我当然必须关心服务器的某些配置,这通常是RESTful服务中的资源位置。抱怨使用动态词汇似乎不公平,因为无论如何我们都必须动态地推理如何理解这种配置。RESTful服务描述了您可以通过超媒体识别对象结构而进行的转换。

我只是不明白什么使固定的词汇表比任何自我描述的动态词汇表更好,后者可以在类似RPC的服务中很好地工作。这仅仅是限制HTTP协议词汇量的不好理由吗?

反射

只是为了澄清我的想法比我做的更好。假设您正在设计任何通用的API,甚至可能都不是面向Web的。如果有人说您只能在对象上使用这些方法名称,您会感到高兴吗?REST不仅限于HTTP,而是考虑您编写的每个API,面向Web或以其他方式仅由包含GET POST PUT和DELETE方法的对象组成的API的情况。因此,您无法定义该object.foo方法。您必须定义一个名为foo的新对象,并调用其GET方法。从本质上讲,这就是REST的工作方式,这让我有些不舒服。您对foo的作用没有更好的一般理解,只是被迫为本质上是父对象上的方法创建一个新对象。此外,您的API同样复杂,通过创建更多对象,您隐藏了接口的复杂性。RESTful Web服务迫使我们采用一个接口,该接口在我们要公开的API上下文中可能足够,也可能不够。也许有很好的理由使用面向Web的API来执行此操作,但是有理由不为每个通用API中的每个对象采用标准接口。一个实际的例子将不胜感激。


为了帮助用户快速解析您的问题和答案,您可以考虑将“更新”添加为单独的答案(尤其是“另一个更新”部分)。鼓励这样做:blog.stackoverflow.com/2011/07/…–
Johann

@Johann,谢谢,现在有进一步的更新,它是该问题的公认答案。
马特·埃施

Answers:


9

“动词”和“名词”这两个术语在这里有些不幸。如前所述,您可以轻松创建功能对象。除Java之外,所有面向对象的语言都内置了该转换,在Java中,您总是会一直进行转换,最终会用单个方法结束许多对象,并且通常使用一种称为“调用”,“执行”,“应用”或类似方法的对象。 (因此在编程语言中,“动词” /“名词”的区别实际上是没有意义的)。

REST的“动词”更像是将您的方法分类为获取器,设置器(删除器;可以认为是设置器的一种)等。并尝试使用getter和setter进行所有操作。原因是:

  1. 由于getter和setter都是幂等的,因此在通信失败时语义更容易。两次获取资源没有任何其他效果,也没有将其设置为已经拥有的值。
  2. 定义一些可能被不了解特定接口的代理缓存所使用的语义。获取器被缓存,并且已知setter使缓存无效。

HTTP从一开始就设计了缓存和容错功能,因此这两点引出了它的四种基本方法:

  • GET是吸气剂。假定每次都不能修改服务器状态并返回相同的值,并且可以指定到期和重新验证策略。
  • PUTDELETE是设置器和删除器(=带有nil的设置器)。它们通常不用于普通Web上下文,但对于REST有意义。
  • POST 是通用的“调用”厨房水槽,对于该水槽,缓存无法承担任何作用。

REST是一种设计模式,描述了如何使用原始HTTP或类似的网络协议来实现接口,该接口允许通过简单的重试就可以轻松处理故障,并且可以很好地与缓存代理一起工作。

它与常规的面向对象的编程API并不容易对应。我认为这实际上是一件好事。通过网络进行接口的挑战本来就不可靠,并且往返比传输少量数据要慢得多,因此需要使用与进程内API不同的设计方法,因此,当看上去不同时,人们不会尝试应用来自其他领域的大量无效经验(这是SOAP,XML-RPC等的祸根;它看起来像过程调用,但是却不能像它那样工作,最终导致工作痛苦)。


2

基本思想是通过资源表示来表达复杂性,因此不需要其他动词。正如某些人所说的那样-“在REST中,名词是好的,动词是不好的。”

如果您查看这四个REST动词,则可以将它们映射到基本的CRUD操作,从本质上讲,您可以使用自己的资源进行任何操作。那是 -

POST-创建资源

GET-阅读资源

PUT-更新资源

删除-删除资源

你还需要什么?


我可以通过创建用于执行此操作的资源来促进RESTful服务中的动词。如您所说,我不需要更多的动词就可以了。我只是不明白为什么当我想做的实际上是一个动词时,最好装一个抽象动词是一个名词。似乎动词无缘无故地受到了限制,我通过创建名词来避免问题,该名词在使用少量动词进行访问时会执行所需的动作。为什么这样做会更好呢?我有一个很好的理由,我可以量化为一个实际例子。
马特·埃施

4
获取所有资源的列表,获取具有给定约束的所有资源的列表,同时更新或删除一堆资源,原子地一起创建两种不同类型的资源(以使创建失败或成功),删除所有资源满足给定条件...可能要做的事情很长。可以使它们适合REST API,但这并不总是自然的。GET不允许正文也无济于事,因此复杂的过滤条件变得笨拙。
安德里亚(Andrea)2012年

修补资源也很酷。
Wyatt Barnett 2014年

2

考虑一种所有构造(例如函数)都是对象的语言。然后,RESTful动词只是调用约定和赋值语句。对于JavaScript,您可以定义固定的动词语法,例如INVOKE(用于调用函数),DELETE(与js中的delete)(用于删除另一个对象上的对象),SET(用于分配值)和RETURN(用于返回值)。我们可以使用HTTP动词来表示等效的POST-调用函数,PUT-分配值,GET-返回值,-DELETE-删除对象。我被HTTP方法实际上是在描述对象方法,实际的对象接口的想法所困扰,但我没有看到它实际上可以描述更低级别的概念,例如,基本语言结构在所有情况下都是固定的和有限的。理智的语言。

当然,对路由/代理有一个固定的词汇进行反思会很有帮助。


1
  • 因为专业的程序员会期望成百上千个方法名称,否则就不会成千上万个方法名称。随着应用程序的变大,在较小的情况下看起来毫无意义的事情可能会变得非常重要。

  • 因为已经定义了方法名称,所以不需要有关它们的标准。

  • 因为代码的主要目标是无需此类附加翻译即可可读。

  • 因为它鼓励和帮助识别“何时”,所以应该打破另一类。

  • 当您接管代码时,合理且实际上可能更快地了解其内容和方式。

  • 它提供了通用的词汇表以及抽象级别,因此您可以专注于其他细节并查看模式。

  • 由于易于检查常见的代码和方法,因此使查找错误更加容易。

  • 当您使用多个“层”(例如,Web开发中的层)进行工作时,知道哪些URL与哪些操作名称匹配对于调试非常方便。

总体而言,您并不需要“总是”使用它,但是像大多数标准一样,尝试使用它非常有意义!


按顺序解决1)那么,程序员是否期望数百甚至数千个资源?我们已经在使用的库中预期了方法。2)因此我们需要方法名称而不是资源名称的标准?我没有遵循那种逻辑。3)不确定翻译的意思。如果您告诉我资源存在,我必须了解它。如果我告诉您存在一种方法,则必须了解它。我真正关心的唯一事情是我的所作所为会有副作用4)你能扩大
马特阿尔泽特

5)你可以再扩大一次。我是电脑程序编制员。我习惯于使用定义明确的对象结构。如果真的更好,为什么不使用这种相同的机制来定义所有API?6)没有理由就没有抽象级别值得考虑。7)同样,您可以扩展。如果我们肯定会从中受益,那么我们应该像这样编写所有的API。8)我希望任何对象都能直接公开其方法。/ object / method不能混淆。我们通过选择采用标准来定义它们。我目前缺乏动力。
马特·埃施

马特,您似乎有点争论,但我会说2)我不是说资源不需要标准3)您将不需要了解诸如“更新”,“新”或“创建”之类的方法,因为您完全知道它们按照标准做什么。但是,“ MsgToPrimary”怎么办?创建一个味精?更新状态?发送电子邮件?7)是的,大多数API都可以从中受益,许多也可以。我将尝试着重关注标准标准和约定,这对我很有帮助,我可以看到您的更新显示了这一点。
Michael Durrant 2012年

我只是在努力理解好处。需要解决强烈的反驳,以澄清问题。我仍然了解固定的动词集只是某种语言描述,但我并不完全同意它使理解变得更容易。您不能带走一组表达动词并说“嘿,当我们不了解所有资源时,我们现在可以理解所有动词了”。资源正在取代动词。我们将任意动词foo替换为称为foo的资源。我们对foo的理解并不比foo为动词时更清晰。
马特·埃施

1

另一种选择是令人恐惧的:WSDL(又名Web服务定义语言),这是一种(笨拙的)方式以编程方式描述(某种程度上)任意APIS。

REST严格限制了动词,将几乎所有特定于应用程序的变体推送到文档的有效负载中。这样做的好处是许多客户端实现可以与许多异构服务进行通信。客户端和服务器可能彼此完全未知,其中一些尚未写入。

有一个播客,其中Stefan Tilkov很好地解释了REST


1

是的,rest api具有一组固定的动词,但不必限于(或包括GET,POST,PUT,DELETE)。我将把GET,POST,PUT,DELETE视为REST的默认实现,它可用于所有系统的80%。

其他实现比crud操作更多的系统可以(并且确实)为其REST API实现自己的动词。可以在REST系统中添加和实现动词,例如发布,使用,评分,评论,搜索,浏览。虽然有些人可能会说更大的词汇量可能会使它变得更复杂,但我的回答是这取决于情况。如果您的目标用户是了解POST是什么的技术负责人,那么可能会更复杂。但是,如果您的API的目标用户是真实的人(即,不编写代码也不知道POST是什么的人),那么真实的动词就容易使用得多。实际上,为您的API设置一组适当的动词有助于使网址保持简短(如果您希望用户在浏览器中输入网址,这一点很重要。如果您使用自定义词汇表,d要确保您的API及其动词有完整的文档记录。使用自定义REST API时,您需要确保将“只读操作”作为HTTP GET和“写操作”与POST一起使用。

青少年社交网络Piczo.com(愿它安息)具有扩展的REST API(包括上述动词),该API已以7种不同的语言实现!


0

简单就是好。

在某些情况下,您需要额外的动词和复杂性,但是大多数问题可以简化为对资源执行简单的CRUD操作,这就是REST试图推广的问题。当您考虑大多数Web应用程序时,最后它们将读取记录并保存在数据存储中,这些记录使用相同的非常简单的操作。

object.foo()都很好,但是它做什么呢?返回的是什么?它是在修改对象的状态或其任何依赖项吗?您能否两次调用它并获得相同的结果,还是会给您两个不同的值?如果还具有object.bar(),是否需要以特定顺序调用它们?

使用丰富的API需要大量知识,而且它们通常都有自己的约定(即setFoo将使对象变异,getBar可能是幂等的,dispose()或destroy()意味着对同一对象没有其他调用可能,等等...)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.