REST / HATEOAS - HAL链接中的可用方法

时间:2017-07-06 09:18:53

标签: json rest api hateoas

我正在考虑使用HATEOAS定义REST API。特别是,我发现非常有趣的是为给定资源指示现在可用的操作。

一些HATEOAS规范包含了太多的开销以满足我的需求,所以我看着HAL specification,因为我发现它非常简洁实用:

{
    _links: {
        self: { href: "/orders/523" },
        warehouse: { href: "/warehouse/56" },
        invoice: { href: "/invoices/873" }
    },
    currency: "USD",
    status: "shipped",
    total: 10.20
 }

但是,HAL中的链接仅包含相关资源的列表,但不包含对它们的可用操作。按照上面的例子,我现在可以取消订单,或者不再订购?一些HAL示例通过使用特定URL进行取消来解决此问题,并且只有在可以取消时才在响应中添加相应的链接:

"cancel": { "href": "/orders/523/cancel" }

但那不是很RESTful。取消不是资源。取消是资源的删除,即:

DELETE /orders/523

有没有一种很好的方法用HAL表示这个,或者我应该使用不同的HATEOAS规范?

我正在考虑使用与self相同的URL返回“取消”链接,但在这种情况下,客户端必须知道要取消它们必须使用DELETE谓词,这在HATEOAS响应中并未真正描述

self: { "href": "/orders/523" },
cancel: { "href": "/orders/523" }

根据HATEOAS / HAL,这是推荐的方法吗?我理解HAL没有任何“方法”参数,自己添加它将违反HAL规范。

2 个答案:

答案 0 :(得分:2)

  

一些HAL示例通过使用特定的URL进行取消来解决此问题,并且只有在可以取消时才在响应中添加相应的链接

是。就像网站一样:如果您想提醒客户端达到其他应用程序状态的可能性,您需要为客户端提供一个链接,包括所涉及资源的标识符。

  

但那不是很RESTful。

它可能不是" RESTful",但它肯定符合REST architectural style

  

取消是资源的DELETE,即:DELETE / orders / 523

您将域模型上的操作与集成模型上的操作混淆。 REST API的作用是引导客户端通过协议来实现某些目的; 语义映射到HTTP上。

Jim Webber这样说:

  

网络不是您的域名;它是一个文件管理系统。所有HTTP谓词都适用于文档管理域。 URI不会映射到域对象 - 这违反了封装。工作(例如:向域模型发出命令)是管理资源的副作用

其中一个REST约束是uniform interface;在HTTP的情况下,它意味着所有资源以统一的方式理解方法; DELETE 表示 RFC 7231, section 4.3.5中描述的语义。

换句话说,如果我发送请求

OPTIONS /x/y/z/foobar ...

并且响应包括Allow header中的DELETE,然后我就知道这意味着什么。您域中的副作用?我对副作用一无所知。

在DELETE的定义中,请注意以下内容

  

相对较少的资源允许使用DELETE方法 - 它主要用于远程创作环境,其中用户对其效果有一些指导。

无论如何,你并不是真的在询问DELETE,而是关于HAL

  

有没有一种很好的方法用HAL表示这个,或者我应该使用不同的HATEOAS规范?

据我所知,正式的做法是用链接关系来记录它。换句话说,而不是使用"取消"作为链接关系,你使用像

这样的东西
  

https://tools.ietf.org/html/rfc5023#section-5.4.2

然后您的消费者,如果他们想要发现链接的用途,可以按照关系来了解正在发生的事情。

HAL Discuss: Why No Methods?有很多好消息。

我喜欢Mike Kelly的总结:

  

这个想法是可以通过链接传达可用的方法   关系文档,不需要在json消息中。

答案 1 :(得分:1)

根据Lost Techies的this article,从CQRS角度来看,它接受使用诸如/orders/<id>/<command>之类的URL并通过PUT请求调用它们。因此可以使用"cancel": { "href": "/orders/523/cancel" }

但是,如果您绝对要使用DELETE并且仅使用命令链接来修改您的资源(即/orders/<id>/<command>)(如本文中所建议的那样),那么为什么不能只添加诸如{{1}并减去HTTP动词? 我的意思是根据REST,只有5个主要动词(GET,POST,PUT,PATCH和DELETE)。我们不能在"cancel": { "href": "/orders/523" }之类的URL上使用POST,GET已经定义为“自我”关系,我们在上面提到,修改(PUT)将由命令链接(即/<ressource>/<id>)处理。并且由于我们使用命令链接,因此无需使用PATCH。之后,剩下的唯一选项是:DELETE。

这不是完美的,但是它可以正常工作并且不会违反任何约定。