遵循HATEOAS原则,每个州都应该被超链接,对改变资源状态的链接进行建模的最佳方法是什么?
让我们用订单的经典例子:
{
id : 12,
state: 'pending',
...,
links: [
...,
{
rel: 'cancel',
href: '/orders/12/cancel'
},
...
]
}
我对“/ cancel”部分感到满意 - 如果我能发送带有内容的“ PUT ”请求,我会感觉好多了:
{
status:'cancelled'
}
但是如何用链接部分中的“href”属性表示?我想在那里代表可用的行动,例如,取消订单并非总是可行('已完成'状态)。
一种可能性是使用像'/ orders / 12?action = cancel'这样的URL,它有点像RPC方法,我错过了什么。
看起来可能最好的另一种可能性就是拥有这样的链接:
{
rel: 'cancel',
href: '/orders/12/',
type: 'PUT',
values: {
state: 'cancelled'
}
}
这个解决方案可能感觉有点冗长。
任何想法如何优雅地处理?也许有人已经解决了类似的“问题”?
答案 0 :(得分:8)
建模资源是REST中最困难的部分。严格遵守标准意味着如果您发现自己曾经这样做过:/resource/:id/{action}
,您违反了“正确使用HTTP”标准,因为您的终端理想情况下应该始终是“名词”,绝不是“动词”(动词)是HTTP协议提供的。)
因此,虽然“它取决于”(即设计资源的难点),但通常: 对象模型状态可以被视为资源本身。
这意味着,您的订单状态实际上是您可以查询的资源(作为独立的/orderstatuses
资源或作为子资源,例如。/orders/:id/status
)
您的应用程序状态现在可以根据订单本身的当前状态链接到状态资源。如果您的“状态”架构看起来像这样(伪):
key: 'status'
values: ['pending', 'cancelled']
然后,您的应用可以PUT /order/:id/status {status:'cancelled'}
(状态良好)返回API,然后取消您的订单。这些术语有点奇怪(RPC更直观),但希望这会有所帮助。
答案 1 :(得分:1)
你必须以某种方式描述形式。你“详细”解决方案是完全可以的:
{
rel: 'cancel',
href: '/orders/12/',
type: 'PUT',
values: {
state: 'cancelled'
}
}
注意:您必须定义自定义MIME类型或使用能够描述表单的通用MIME类型(例如collection + json),或者使用RDF类型(支持像Hydra这样的REST词汇) - 又名。统一界面/自我描述性消息
我想在那里代表可用的行动,例如, 取消订单并非总是可行('已完成'状态)。
如果操作不可用,则不要发送指向该操作的链接。
答案 2 :(得分:0)
我会建议这两种模式中的任何一种。第一个是经典的,但rel="edit-form"
并使用PATCH
。第二种是通过对HTTP资源模型如何映射到应用程序域模型(即,两者不必具有1:1映射)的横向思考而产生的替代方案。
就地编辑资源。
HTML兼容:
HTTP/1.1 200 OK
Content-Type: text/html
Location: /orders/1/
...<a rel="edit-form" href="./edit">Edit</a>...
HTTP/1.1 200 OK
Content-Type: text/html
Location: /orders/1/edit
...
<form action="../" method="POST">
<input type="hidden" name="_METHOD" value="PATCH">
<button type="submit" name="status" value="cancelled">Cancel Order</button>
</form>
...
POST /orders/1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
_METHOD=PATCH&status=cancelled
富客户端(例如HTML + Javascript)兼容:
PATCH /orders/1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
status=cancelled
和/或
PATCH /orders/1 HTTP/1.1
Content-Type: text/json
{
"status": "cancelled"
}
由于HTML缺乏对HTTP的支持,_METHOD
密钥是一种众所周知的为REST框架提供正确方法的方法。
或者,删除资源(顺便提一下,创建一个新资源)
DELETE /orders/1 HTTP/1.1
HTTP/1.1 201 Created
Location: /cancelled-orders/1
有关将网络资源映射到域对象的更多信息,请see my answer提出类似的问题。
您可能希望阅读的另一个答案是this one。