我有一个基本的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中更改多个项目,并且在按下“保存”时将发送请求。这包括更新当前项目,还添加新项目或删除项目。不允许部分成功。覆盖每个用例的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}
优点:干净的体系结构。您可以使用实体的端点添加/更新/删除实际的实体。
缺点:如果用户更新500个项目并单击“保存”,则将向服务器发送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件商品添加到订单,那么在一个请求(对PUT
实体的Order
请求)中,我们将本质上在不同的商品上添加,更新和删除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将以“项目”结尾。这是怎么做的?
解决方案D:可能使用PATCH
的其他解决方案?以前从未做过,但是也许可以为PATCH
实体发送Order
,从而修补Items的集合。以JsonDocument的价值,我将传递新项目的集合,要删除的项目和更新的项目?
因此,我的问题是:这些解决方案中哪种最适合这种情况? A,B,C或(如果存在)D?还是其他我没想到的解决方案?
如果您没有很多项目,解决方案A完全可以。它不适合您的情况,因为如果您有很多请求,它会使您的api变得不友好。
解决方案B一次发送了很多。它坚持使用完整资源对象进行更新的做法,甚至还有一个http状态代码来指示部分成功。响应对象是一个让消费者知道成功的新URL并指出失败的URL的考虑因素(如果有)以及原因。随它或D。
解决方案C并没有那么轻松。您实际上并没有更新任何单一资源,因此对于消费者而言将很难理解。
解决方案D是B和C的合并。我希望在这里使用它,因为您并没有真正更新完整的对象。您可以使用与B相同的网址
几个扩展超文本传输协议(HTTP)的应用程序需要功能来进行部分资源修改。现有的HTTP PUT方法仅允许完全替换文档。该提案添加了新的HTTP方法PATCH,以修改现有的HTTP资源。– RFC 5789