REST:当一个请求改变多个实体的状态时返回什么?

Tom*_*mes 5 rest restapi

REST 服务有两个节点

GET/items返回项目列表:

[
  {
    "id": 34,
    "name": "apple",
    "available_amount" : 10
  },
  {
    "id": 37,
    "name": "banana",
    "available_amount" : 30
  },
  ...
]
Run Code Online (Sandbox Code Playgroud)

POST/orders使用请求的项目创建订单(假设我们在这里订购 6 个苹果)并返回订单:

{
  "id": 12337,
  "items": [
    {
      "id": 34,
      "name": "apple",
      "ordered_amount": 6
    }    
  ]
}
Run Code Online (Sandbox Code Playgroud)

我如何将创建的订单通知客户端应用程序,该订单也减少了available_amount4因为6苹果已售出。

我是否将受影响的资源与order结果一起返回,以便客户端知道要更新什么?

像节点路径:

{
  "id": 12337,
  "items": [
    {
      "item_id": 34,
      "ordered_amount": 6
    }
  ],
  "affected_resources" : [
    "/items/34"
  ]
}
Run Code Online (Sandbox Code Playgroud)

甚至完全改变的资源:

{
  "id": 12337,
  "items": [
    {
      "item_id": 34,
      "ordered_amount": 6
    }
  ],
  "affected_resources": {
    "items": [
      {
        "id": 34,
        "name": "apple",
        "available_amount": 4
      }
    ]
  }
}

Run Code Online (Sandbox Code Playgroud)

或者完全不同的东西?

在这些情况下,什么被认为是最佳实践?

Kit*_*Kit 5

您的请求是创建单个新订单资源的 POST。

虽然其他资源可能发生的事情与客户端有关,但只有当这些资源处于相同的有界上下文中时,这才是正确的。库存显然是一个不同的有界上下文。

至少只发送当时您认为正确的内容,即新订单的 ID 或新订单的表示。故事可能还有更多……

以每秒 1000 个订单的速度,您可能会发送有关库存的无效数据。

现在,如果通知客户他们的苹果和香蕉订单确实是“苹果和香蕉订单”,那么您可以安全地告诉您的客户;这是一个很好的功能,因为您正在将客户端发送给您的状态传输回客户端,这是事实。您甚至可以告诉客户他们订购了多少。还是实话。说你还剩 N 个苹果和 M 个香蕉……那可能是个谎言。

当我们在这里讨论资源时,它们与DDD意义上的实体不同,但有足够接近的近似值。资源通常(但不总是)是 DDD 实体(以及扩展聚合)的表示。您的 API 通常会针对单个有界上下文进行操作,因此引入库存等概念显然不在排序有界上下文中。

如果您想让库存成为客户感兴趣的东西,那就是一个单独的 API。

短篇小说

两个客户下订单。您的 API 尽职尽责地接受他们的命令。

客户 A 是零售客户,只想要他们的东西。你告诉他们你收到了他们的订单(一本关于 REST 的书,还有一个云订阅,对吧?),客户看到订单跟踪链接,并开始请求订单状态。“我的东西呢?”

客户 B 是一家批发商,要求提供 1000 本书,以便在转售时手头有这些 REST 书籍。您将他们的订单发送给他们,其中还包含指向图书库存的链接。客户 B 很高兴,因为这些书卖得很快,并且需要询问您(当然是通过您单独的 API)您是否还有 500 本书。您的其他 API 检查库存并说“我现在可以给您 500 个,但这仅适用于接下来的 15 分钟……”

简而言之,我会说返回任何信息,从指示 POST 成功的最小信息量(一个 ID 和一个201响应代码)到最大量(关于客户端发送它时正确的订单的所有信息,以及任何相关的信息)这也保证在有界上下文中是真的)。

API 的理想选择是将资源的表示传达给客户端,客户端可以合理地成功执行这些表示。这包括有关资源的数据和表示客户端可以采取的操作的数据。

虽然这有点超出您的问题,但HATEOS在这方面提供了很多指导(博客文章)。


Mar*_*k H 1

最佳实践是返回订单创建请求的成功/失败,并可选择包含成功或错误消息。根据该返回状态向客户通知已创建(或未创建)的订单。任何新的库存 GET 请求都将由客户端在认为合适时完成。也就是说Application State应该维护在客户端;REST API 应该使用无状态协议

我不确定您在编程什么,但无论是全部还是全无,或者您可以部分履行订单,明智的做法是为每个项目 id 返回成功和失败响应。在这种情况下,如果订单格式有效,则总体响应将成功(否则失败),然后是包含 item_id、amount_ordered、amount_fulfilled 的响应数组。在全有或全无的情况下,这可能会调用订购的第二阶段,您通知用户某某商品的库存有限或已售完,他们是否想要调整订单或取消订单。

要更新库存,如果您允许客户端将感兴趣的商品作为 inventory/items GET 请求中的参数传递,您可以对客户端进行编程,以根据用于创建订单的商品列表请求库存更新。 POST 请求。这将是客户端维护其应用程序状态的示例,即“在最后订单中订购的商品将需要新的库存检查”。