HATEOAS和链接/操作

时间:2016-09-12 19:40:42

标签: rest api-design hateoas json-api hypermedia

我试图围绕如何(以及如果)在我的api中实现HATEOAS。我喜欢在客户端仅提供适合当前情况的操作的概念之一。但是,我不确定我是否正确实现了这个想法。

我们说我有一个资源类型订单,状态可以更改,它可以有不同的状态(处理接受< / em>,已拒绝已过期,已成功)。我应该创建以下json对象:

{
    ...
    "links": {
        "accept": "http://example.com/order/1/accept",
        "decline": "http://example.com/order/1/decline"
    }
}

或者我在这里创建不必要的行动?如果以上是正确的,应该通过PATCH更改状态还是GET?如果它是PATCH,那怎么会知道(击败超媒体的目的)?

修改:忘记添加订单ID

1 个答案:

答案 0 :(得分:5)

  

假设我有一个资源类型订单,其状态可以更改,它可以具有不同的状态(处理,接受,拒绝,过期,成功)。

警告:除非您的域名恰好是文档管理,否则如果您尝试将资源与域概念相匹配,可能会让自己陷入困境。吉姆韦伯warned about this years ago;在大多数情况下,您的资源是集成域的一部分。它们是用于与您的域模型交互的小数码纸。

{
    ...
    "links": {
        "accept": "http://example.com/order/accept",
        "decline": "http://example.com/order/decline"
    }
}

这里的基本想法很好 - 如果客户想要调用接受协议,他们知道要使用哪个链接;同样适用于拒绝协议。除此之外,客户知道它不应该尝试做,因为链接不可用;例如,如果客户的目标是使订单到期,它就会知道它已经陷入了死胡同。

URI的拼写有点奇怪;客户端不应该关心拼写,但请求应该是无状态的。如果订单是资源的类型,那么您如何沟通接受/拒绝哪个订单。

  

如果上述情况正确,是否应通过PATCH更改状态,还是GET?

都不是。

GET 是错误的,因为宣传资源支持GET是声称操作安全,这意味着中间组件可以推测性地遵循链接,加载结果以节省客户端时间。如果您理解传达客户端做出的决定的消息

,那么您不想做什么

PATCH 有两个问题。首先,它是为文档操作而设计的;如果您的应用程序是文档数据库,那么PATCH非常适合进行一个或多个范围更改。但是处理业务模型的代理表示并不是那么好;客户端传达其意图对表示的副作用,而不是客户端将其意图传达给服务器,然后服务器尝试从副作用中推断出意图。

但是你可以解决这个问题;毕竟,您可以选择支持的媒体类型,并可能将自己限制在那些允许您表达客户意图的类型中。

第二个问题是PATCH不是幂等的;它具有与POST相同的故障模式 - 如果服务器未确认请求,则客户端无法轻易确定重试请求是否安全。

直接的做法是将编辑视为类似于将手写笔记放入某人的收件箱

  

应接受订单54321。请完成它。   签名,客户。

换句话说,我们不是试图直接操纵订单资源,而是将注释发送到收件箱,这会产生操纵订单的副作用。客户端描述了它想要的更改,服务器进行更改(如果允许服务器具有自治权,则不进行更改)。

对于这种方法,PUT(幂等)或POST(不是)是合适的。实际上,您正在向收件箱集合添加新消息,并且可以使用该成语来选择合适的方法。

  

如果是PATCH,那怎么会知道(挫败超媒体的目的)?

客户如何知道在“链接”属性中查找链接?

浏览器如何知道如何处理HTML文档中的链接?

REST的答案是:他们知道,因为您在设计媒体类型本身时投入了大量精力。在Web的情况下,在设计text / html媒体类型方面投入了大量的时间和精力,因此任何设计了html的客户端都可以使用由共享该理解的服务器生成的表示 - 客户端和服务器彼此分离,但有一个共同点。

对于HTML,大多数情况下,媒体类型定义与链接关联的HTTP方法(例外是表单,允许表示从受限集中指定方法)。站在巨人的肩膀上。