我试图围绕如何(以及如果)在我的api中实现HATEOAS。我喜欢在客户端仅提供适合当前情况的操作的概念之一。但是,我不确定我是否正确实现了这个想法。
我们说我有一个资源类型订单,状态可以更改,它可以有不同的状态(处理,接受< / em>,已拒绝,已过期,已成功)。我应该创建以下json对象:
{
...
"links": {
"accept": "http://example.com/order/1/accept",
"decline": "http://example.com/order/1/decline"
}
}
或者我在这里创建不必要的行动?如果以上是正确的,应该通过PATCH更改状态还是GET?如果它是PATCH,那怎么会知道(击败超媒体的目的)?
修改:忘记添加订单ID
答案 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方法(例外是表单,允许表示从受限集中指定方法)。站在巨人的肩膀上。