【问题标题】:How to update a collection in Web API?如何更新 Web API 中的集合?
【发布时间】:2019-12-14 01:23:18
【问题描述】:

我有一个基本的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 中的多个项目,并在按下“保存”时发送请求。这包括更新当前项目,还包括添加新项目或删除项目。不应允许部分成功。

涵盖每个用例的 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:一一更新Order的商品,所以端点:

  • [POST] /api/orders/{orderId}/items,有效载荷:{ "quantity": 25, "price": 50 }
  • [PUT] /api/orders/{orderId}/items/{itemId},有效载荷:{ "quantity": 25, "price": 50 }
  • [DELETE] /api/orders/{orderId}/items/{itemId}

优点:干净的架构。您使用实体的端点添加/更新/删除实际的实体。

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

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

{
    "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 和有效负载:

立即更新 Order 的项目
[
    {
        "itemId": 112233,
        "quantity": 25,
        "price": 50
    },
    {
        "itemId": 445566,
        "quantity": 20,
        "price": 40
    }
]

payload中的集合,将完全替代系统中的集合,包括添加和删除操作。

优点:性能,不允许部分成功,不要与父实体混淆。

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

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

所以,我的问题是:哪种解决方案最适合这种情况? A、B、C 还是(如果存在)D?还是我没有想到的其他解决方案?

【问题讨论】:

  • 似乎解决方案 B 最符合您的要求,但它让您担心,因为在一个请求中会发生很多事情。如果每个部分(添加/删除项目等)在概念上都是一件事 - 订单更新,我真的不认为这是一个问题。
  • 解决方案 B 对我来说似乎是最好的解决方案。
  • 解决方案 B 对我来说似乎是最好的解决方案。如果你愿意,你也可以添加 A,但在内部我可能会调用 B。你想在事务中一次更新,所以发送 50 个单个请求对我来说听起来是错误的。

标签: c# rest asp.net-web-api url-routing asp.net-core-webapi


【解决方案1】:

如果您没有很多项目,解决方案 A 完全可以。它不适合您的情况,因为如果您有很多请求,它会使您的 api 变得健谈。

解决方案 B 一次发送很多。它坚持使用完整资源对象进行更新的做法,甚至还有一个 http 状态码表示部分成功。响应对象是一个考虑因素,让消费者知道成功的新 url 并指出失败的那些(如果有的话)和原因。随它去吧,否则 D。

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

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

几个扩展超文本传输​​协议 (HTTP) 的应用程序 需要一个特性来做部分资源修改。现有的 HTTP PUT 方法只允许完全替换一个文档。 该提案添加了一个新的 HTTP 方法 PATCH 来修改现有的 HTTP 资源。 – RFC 5789

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-10
    • 2015-05-10
    • 2014-09-25
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    相关资源
    最近更新 更多