9

遵循 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'
  }
}

这个解决方案可能感觉有点冗长。

任何想法如何优雅地处理?也许有人已经解决了类似的“问题”?

4

4 回答 4

10

建模资源是 REST 中最困难的部分。严格遵守标准意味着如果您看到自己曾经这样做过:/resource/:id/{action},您违反了“正确使用 HTTP”标准,因为理想情况下,您的端点应该始终是“名词”,而不是“动词”(动词是 HTTP 协议提供)。

因此,虽然“它取决于”(即设计资源的困难部分),但通常: 对象模型状态可以被视为资源本身

这意味着,您的订单状态实际上是您可以查询的资源(作为独立/orderstatuses资源或子资源,例如。/orders/:id/status

您的应用程序状态现在可以根据订单本身的当前状态链接到状态资源。如果您的“状态”架构看起来像这样(伪):

key: 'status'
values: ['pending', 'cancelled']

然后,您的应用程序可以PUT /order/:id/status {status:'cancelled'}(格式良好的状态)返回 API,然后 API 将采取行动取消您的订单。用这些术语来说有点奇怪(RPC 更直观),但希望这会有所帮助。

于 2013-07-25T14:04:58.297 回答
1

你必须以某种方式描述形式。您的“冗长”解决方案完全可以:

{
  rel: 'cancel',
  href: '/orders/12/',
  type: 'PUT',
  values: {
    state: 'cancelled'
  }
}

注意:您必须定义自定义 MIME 类型或使用能够描述表单的通用 MIME 类型(例如集合 + json),或者 RDF 类型(支持像 Hydra 这样的 REST 词汇) - 也就是。统一的界面/自我描述的消息

我想在那里表示可用的操作,例如,取消订单并不总是可能的(“完成”状态)。

如果某个操作不可用,则不要发送指向该操作的链接。

于 2013-10-07T07:25:20.800 回答
0

我会推荐这两个模型中的任何一个。第一个是经典的,但在可用的地方使用rel="edit-form"和使用PATCH。第二种是通过横向思考 HTTP 资源模型如何映射到您的应用程序域模型(即两者不必具有 1: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"
}

_METHOD关键是一种众所周知的为 REST 框架提供正确方法的方法,因为 HTML 缺乏对 HTTP 的支持。


解决方案 2

或者,删除资源(顺便创建一个新资源)

DELETE /orders/1 HTTP/1.1

 

HTTP/1.1 201 Created
Location: /cancelled-orders/1

有关这种将 Web 资源映射到域对象的方式的更多信息,请参阅我对类似问题的回答。

您可能希望阅读的另一个答案是这个

于 2013-07-21T09:55:52.900 回答
0

除了papercowboy的回答,在状态转换并不总是可用的情况下,您可以记录当前可能作为资源的内容,例如

/order/:id/availableStates

{
    "availableStates": [
        {"status": "cancelled"}
    ]
}
于 2017-08-11T10:59:13.567 回答