1

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

假设我有一个可以更改状态的资源类型订单,它可以有不同的状态(处理接受拒绝过期、成功)。然后我应该创建以下 json 对象:

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

还是我在这里创建了不必要的操作?如果上面是正确的,状态应该由 PATCH 还是 GET 来改变?如果是 PATCH,怎么会知道(违背超媒体的目的)?

编辑:忘记添加订单ID

4

1 回答 1

7

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

警告:除非您的领域恰好是文档管理,否则如果您尝试将您的资源与您的领域概念相匹配,您可能会陷入困境。吉姆·韦伯(Jim Webber)几年前就警告过这一点;在大多数情况下,您的资源是集成域的一部分。它们是用于与您的域模型交互的小数字纸片。

{
    ...
    "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 方法(表单例外,它允许表示从受限集中指定方法)。站在巨人的肩膀上。

于 2016-09-12T23:03:02.120 回答