如何更新 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; }
}
我想涵盖的用例:
- 添加
Order
有很多 OrderItems
- 更新
Order
的属性,例如 IsVoided
- 更新
Order
的项目(一次更新多个项目)。含义 - 用户将更改 UI 中的多个项目,并在按下 "Save" 时发送请求。这包括更新当前项目,还包括添加新项目或删除项目。不应该允许部分成功。
API 涵盖每个用例的 URI:
- 添加
Order
有很多 OrderItems
:[POST] /api/orders/
有效负载:
{
"customerId": 805,
"isVoided": "false",
"items": [
{
"itemId": 112233,
"quantity": 25,
"price": 50
},
{
"itemId": 445566,
"quantity": 20,
"price": 40
}
]
}
- 更新
Order
的属性,例如 IsVoided
(但不是项目):[PATCH] /api/orders/{orderId}
[
{
"op": "replace",
"path": "/IsVoided",
"value": true
}
]
- 更新
Order
的项目(一次多个项目)
这是我遇到的问题...我有一些想法:
解决方案 A: 逐一更新订单的项目,因此端点:
[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}
优点:简洁的架构。您 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
我有一个基本的 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; }
}
我想涵盖的用例:
- 添加
Order
有很多OrderItems
- 更新
Order
的属性,例如IsVoided
- 更新
Order
的项目(一次更新多个项目)。含义 - 用户将更改 UI 中的多个项目,并在按下 "Save" 时发送请求。这包括更新当前项目,还包括添加新项目或删除项目。不应该允许部分成功。
API 涵盖每个用例的 URI:
- 添加
Order
有很多OrderItems
:[POST] /api/orders/
有效负载:
{ "customerId": 805, "isVoided": "false", "items": [ { "itemId": 112233, "quantity": 25, "price": 50 }, { "itemId": 445566, "quantity": 20, "price": 40 } ] }
- 更新
Order
的属性,例如IsVoided
(但不是项目):[PATCH] /api/orders/{orderId}
[ { "op": "replace", "path": "/IsVoided", "value": true } ]
- 更新
Order
的项目(一次多个项目)
这是我遇到的问题...我有一些想法:
解决方案 A: 逐一更新订单的项目,因此端点:
[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}
优点:简洁的架构。您 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
相同的 urlSeveral 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