如何更新 Web API 中的集合?

How to update a collection in Web API?

我有一个基本的 Order-OrderItem 情况,我正在努力如何在一个请求中更新项目(或者我是否应该?)让我解释一下,我会问问题在最后。

型号:

public class Order
{
    public int OrderId { get; set; }
    public string CustomerId { get; set; }
    public bool IsVoided { get; set; }

    public List<OrderItem> Items { get; set; }
}

public class OrderItem
{
    public int OrderItemId { get; set; }
    public string Name { get; set; }
    public int Quantity { get; set; }
    public int Price { get; set; }
}

我想涵盖的用例:

  1. 添加 Order 有很多 OrderItems
  2. 更新 Order 的属性,例如 IsVoided
  3. 更新Order的项目(一次更新多个项目)。含义 - 用户将更改 UI 中的多个项目,并在按下 "Save" 时发送请求。这包括更新当前项目,还包括添加新项目或删除项目。不应该允许部分成功。

API 涵盖每个用例的 URI:

  1. 添加 Order 有很多 OrderItems[POST] /api/orders/ 有效负载:
{
    "customerId": 805,
    "isVoided": "false",
    "items": [
        {
            "itemId": 112233,
            "quantity": 25,
            "price": 50
        },
        {
            "itemId": 445566,
            "quantity": 20,
            "price": 40
        }
    ]
}
  1. 更新 Order 的属性,例如 IsVoided(但不是项目):[PATCH] /api/orders/{orderId}
[
  {
      "op": "replace",
      "path": "/IsVoided",
      "value": true
  }
]
  1. 更新 Order 的项目(一次多个项目)

这是我遇到的问题...我有一些想法:

解决方案 A: 逐一更新订单的项目,因此端点:

优点:简洁的架构。您 Add/Update/Delete 实际上是实体,使用实体的端点。

缺点:如果用户更新 500 个项目并单击 "Save",将导致向服务器发出 500 个请求。此外,它将接受部分成功

解决方案 B: 通过更新订单立即更新订单的项目:[PUT] /api/orders/{orderId} 有效负载:

{
    "customerId": 805,
    "isVoided": "false",
    "items": [
        {
            "itemId": 112233,
            "quantity": 25,
            "price": 50
        },
        {
            "itemId": 445566,
            "quantity": 20,
            "price": 40
        }
    ]
}

优点:性能,不允许部分成功。

缺点:如果用户更新 50 件商品,删除 50 件商品并向订单中添加 50 件新商品,在一个请求中(对 Order 实体的 PUT 请求)我们基本上会添加、更新,删除了另一个实体上的 50 个项目 - OrderItem。我担心这是否是好的 RESTful 做法。

解决方案 C: 通过更新...立即更新订单的项目集合:[PUT] /api/orders/{orderId}/items 有效载荷:

[
    {
        "itemId": 112233,
        "quantity": 25,
        "price": 50
    },
    {
        "itemId": 445566,
        "quantity": 20,
        "price": 40
    }
]

有效负载中的集合,将完全替换系统中的集合,包括添加和删除操作。

优点:性能,不允许部分成功,您不会弄乱父实体。

缺点:这是对集合调用 PUT 请求的好习惯。通常当你有 PUT 时,URI 以某种 ID 结尾(你正在更新一个实体)。在这种情况下,URI 将以 "items" 结尾。是这样做的吗?

解决方案 D: 一个不同的解决方案,可能 PATCH?以前从未这样做过,但也许可以为 Order 实体发送 PATCH,修补项目集合。在 JsonDocument 的值中,我会传递新项目的集合、要删除的项目和更新的项目吗?

所以,我的问题是:对于这种情况,这些解决方案中哪一个是最好的? A、B、C 或(如果存在)D?或者我没有想到的其他解决方案?

如果您没有很多物品,解决方案 A 完全可以。它不适合你的情况,因为如果你有很多请求,它会让你的 api 喋喋不休。

方案B一次发很多。它坚持使用完整资源对象更新的做法,甚至有一个 http 状态代码来指示部分成功。 Response 对象是让消费者知道新的 url 成功并指出失败的原因(如果有的话)的考虑因素。随它去还是D.

解决方案 C 不是 restful。您并没有真正更新任何单一资源,消费者很难理解。

解决方案 D 是 B 和 C 的合并。我希望在这里使用它,因为您并没有真正更新完整的对象。您可以使用与 B

相同的 url

Several applications extending the Hypertext Transfer Protocol (HTTP) require a feature to do partial resource modification. The existing HTTP PUT method only allows a complete replacement of a document. This proposal adds a new HTTP method, PATCH, to modify an existing HTTP resource. – RFC 5789