我正在考虑使用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规范。
答案 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规范?
据我所知,正式的做法是用链接关系来记录它。换句话说,而不是使用"取消"作为链接关系,你使用像
这样的东西然后您的消费者,如果他们想要发现链接的用途,可以按照关系来了解正在发生的事情。
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。
这不是完美的,但是它可以正常工作并且不会违反任何约定。