使用REST拆分头发:标准JSON REST API是否违反了HATEOAS?

bod*_*ous 40 api rest

我今天早上在REST上做了一些阅读,我遇到了HATEOAS原则("超媒体作为应用程序状态的引擎").

引用REST维基百科页面:

客户端仅通过服务器在超媒体内动态识别的动作(例如,通过超文本内的超链接)进行状态转换.除了应用程序的简单固定入口点之外,客户端不会假定任何特定操作可用于除先前从服务器接收的表示中描述的任何特定资源之外的任何特定操作.

Roy Fielding的博客:

...如果应用程序状态的引擎(以及API)不是由超文本驱动的,那么它不能是RESTful的,也不能是REST API.期.

我将其读作:客户端可能只根据服务器响应主体(超文本)提供的操作请求状态更改.

在HTML世界中,这非常有意义.客户端应该只能根据通过超文本(HTML)提供的链接请求状态更改(新操作/页面).

当资源以其他方式表示时 - 例如JSON,XML,YAML等.这不是那么明显.

我们来看一个示例"REST"JSON API:

我通过发送POST请求来创建新资源(例如新注释)

/comments.json? # with params...

服务器响应:

# Headers
HTTP/1.1 201 Created 
Location: http://example.com/comments/3
Content-Type: application/json; charset=utf-8
... Etc.

# Body
{"id":3,"name":"Bodacious","body":"An awesome comment","post_id":"1"}
Run Code Online (Sandbox Code Playgroud)

我知道我现在可以在标题中返回的URI处访问此评论:http://example.com/comments/3.json

当我访问http://example.com/comments/3.json时,我看到:

{"id":3,"name":"Bodacious","body":"An awesome comment","post_id":"1"}
Run Code Online (Sandbox Code Playgroud)

假设API的文档告诉我可以通过向同一URI发送DELETE请求来删除此注释.这在"REST"API中相当常见.

然而:

来自服务器的响应GET http://example.com/comments/3.json并没有告诉我任何关于能够通过发送DELETE请求来删除注释的信息.它向我展示的是资源.

我也可以使用相同的URL删除注释,这是客户端通过带外信息(文档)知道的,并且不会被服务器的响应发现和驱动.

在这里,客户端假定DELETE操作(以及可能的其他人)可用于这一资源,并且此信息尚未先前从服务器接收.

我是否误解了HATEOAS,或者我是否正确地说,与严格意义上的上述描述相匹配的API不会是REST API?

我知道100%坚持REST并不总是可行或最务实的方式.我发布这个问题纯粹是为了满足我对REST背后理论的好奇心,而不是对现实世界最佳实践的建议.

cur*_*sdf 20

Jon Moore 在2010年11月发表了一篇关于编写真正RESTful(即HATEOAS支持)API和客户端的细节的精彩演讲.在第一部分中,他建议JSON不是REST的适当媒体类型,因为它缺乏一种通常理解的表示链接和支持的HTTP方法的方式.他认为,良好的醇" XHTML实际上是为这个完美的,因为用于解析它的工具(即XPath的)都是现成的,它支持的形式(想获取链接模板和PUT,POST和DELETE方法),并具有一个易于理解的方式识别超链接,以及主要通过在任何标准Web浏览器中使用API​​实现的一些其他优势(简化开发人员,QA和支持人员的工作.)

我在观看他的演讲之前总是提出的论点是,JSON比任何*ML语言(例如XML,HTML,XHTML)都低得多.但是在可能的情况下使用简洁的XHTML,例如相对链接而不是绝对链接(在他的演讲中使用的示例中暗示但不那么明显),并且通过使用gzip压缩,这个论点失去了很多权重.

我意识到JSON-Schema其他 RFC的努力正在尝试用JSON标准化事物,但与此同时,摩尔的谈话使我确信尝试了XHTML.


sui*_*ing 18

作为超媒体类型的JSON没有定义应用程序流的标识符.HTML具有链接和表单标记,用于指导用户完成整个过程.

如果您的应用程序仅涉及资源上的PUT,POST,DELETE,GET,那么您的文档可以很容易地解释这一点.

但是,如果它更复杂,比如在评论中添加反驳,并且反驳是一个不同的资源,那么评论你将需要超媒体类型来指导消费者创建反驳.

您可以使用HTML/XHTML,创建自己的'bodacious + json'或使用其他东西.以下是所有不同的媒体类型 http://www.iana.org/assignments/media-types/index.html

我正在使用HAL,它有一个非常活跃的组.这是它的链接.

http://www.iana.org/assignments/media-types/application/vnd.hal+json

http://stateless.co/hal_specification.html

"使用HTML5和节点构建超媒体API"一书深入探讨了超媒体和媒体类型.它显示了如何在XML或JSON中为特定或通用目的创建媒体类型.


sim*_*ony 15

RESTful解决方案是利用Allow-header向客户端通知可用的方法/操作:

> GET /posts/1/comments/1 HTTP/1.1
> Content-Type: application/json
>
< HTTP/1.1 200 OK
< Allow: HEAD, GET, DELETE
< Content-Type: application/json
<
< {
<  "name": "Bodacious",
<  "body": "An awesome comment",
<  "id":   "1",
<  "uri": "/posts/1/comments/1"
< }
Run Code Online (Sandbox Code Playgroud)

菲尔丁的论文提出了两种类型的元数据:表示元数据 ; 和资源元数据.

HTTP/1.1中的Allow-header用作资源元数据,因为它描述了资源的某些属性; 即它允许的方法.

通过充分利用HTTP提供的功能,您可以消除对任何越界信息的需求,并变得更加RESTful.

简单HTTP上下文中的HATEOAS描述了客户端如何通过使用GET跟随URI从一种表示导航到另一种表示,而Allow-header通知客户端生成该表示的资源所支持的其他方法.

这是一个整洁的设计; 客户端要求表示,并另外收到一大堆关于资源的额外元数据,这些元数据能够有效地请求进一步的表示.

我认为你从维基百科REST页面中得到的引用在选择单词方面有些误导,并且在这里没有帮助(注意,自从提出这个问题以来,它已得到改进).

所有HTTP客户端都必须假设GET方法可能适用于大多数资源.他们这样做是因为对GETHEAD的支持是HTTP/1.1服务器的最低要求.如果没有这种假设,网络将无法运作.如果客户端可以假设GET可用,那么为什么不对常用方法(如DELETEPOST)做出其他假设呢?

REST和HTTP旨在利用对一组基本方法进行假设的能力,以减少网络上的请求总量; 如果请求成功,则无需进一步通信; 但是如果请求失败且状态为"405 Method Not Allowed",则客户端会立即通过Allow-header接收可能成功的请求:

> ANNIHILATE /posts/1/comments/1 HTTP/1.1
> Content-Type: application/json
>
< HTTP/1.1 405 Method Not Allowed
< Allow: HEAD, GET, DELETE
< Content-Type: application/json
<
Run Code Online (Sandbox Code Playgroud)

如果基本的HTTP/1.1方法集不够,那么您可以自由定义自己的方法.但是,在定义新方法或将元数据放入消息体之前,使用HTTP的可用功能解决问题将是RESTful.


Dav*_*uer 8

一个完全可发现的JSON API,它不需要任何带外知识,因为你如此简洁地说:

"我也可以使用相同的URL删除注释,这是客户端通过带外信息(文档)知道的,并且不会被服务器的响应发现和驱动."

......完全有可能.它只需要一个简单的标准和一个理解标准的客户端.查看hm-json和hm-json浏览器项目:

https://bitbucket.org/ratfactor/hm-json-browser/

正如您在演示中所看到的,绝对不需要带外文档 - 只有一个入口点URI,通过浏览可以从中发现所有其他资源及其HTTP方法.

顺便说一下,在起诉的答案中提到的HAL非常非常接近你对HATEOAS的假设要求.这是一个很好的标准,它有很多很酷的想法,比如嵌入式资源,但它没有办法告知客户端所有可用的HTTP方法,例如给定资源的DELETE.

  • 通常,诸如资源的可用方法(GET,POST,PUT,DELETE,PATCH等等)应该在OPTIONS请求的`Allow`响应头中定义. (3认同)

pap*_*boy 5

可以在此处找到另一个解决 JSON 的 HATEOAS 的可靠尝试(截至 2013 年 5 月是新的):

JSON API:http://jsonapi.org/