问题描述
我有一个基本的Order
-OrderItem
情况,我在为如何在一个请求中更新项目而苦苦挣扎(或者我应该吗?)让我解释一下,我将在最后问这个问题./p>
型号:
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; }
}
我要介绍的用例:
- 添加具有很多
OrderItems
的 - 更新
Order
的属性,例如IsVoided
- 更新
Order
的项目(一次更新多个项目).含义-用户将在UI中更改多个项目,并且在按下保存"时将发送请求.这包括更新当前项目,还包括添加新项目或删除项目.不允许部分成功.
Order
涵盖每个用例的API URI:
- 添加具有大量
OrderItems
的Order
:[POST] /api/orders/
带有有效载荷:
- 更新
Order
的属性,例如IsVoided
(但不包括项目):[PATCH] /api/orders/{orderId}
- 更新
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}
一次更新订单的项目:
优点:性能,不允许部分成功.
缺点:如果用户更新了50件商品,删除了50件商品并向订单中添加了新的50件商品,那么在一个请求(对Order
实体的PUT
请求)中,我们将实质上添加,更新,删除订单上的50件商品其他实体-OrderItem
.我担心这是否是很好的RESTful
做法.
解决方案C:通过更新...集合:带有有效负载的[PUT] /api/orders/{orderId}/items
:
有效负载中的集合将完全替换系统中的集合,包括添加和删除操作.
优点:性能,不允许部分成功,您不会与父实体混淆.
缺点:在集合上调用PUT
请求是一种好的做法.通常,当您使用PUT
时,URI以某种种类的ID结尾(您正在更新实体).在这种情况下,URI将以项目"结尾.这是怎么做的?
解决方案D:可能是PATCH
的其他解决方案?以前从未做过,但是也许可以为Order
实体发送PATCH
,以修补Items的集合.以JsonDocument的价值,我将传递新项目的集合,要删除的项目和更新的项目?
因此,我的问题是:在这种情况下,哪种解决方案最合适? A,B,C或(如果存在)D?还是其他我没想到的解决方案?
如果您没有太多项目,则解决方案A完全可以.它不适合您的情况,因为如果您有很多请求,它会使您的api变得不友好.
解决方案B一次发送大量邮件.它坚持使用完整资源对象进行更新的做法,甚至还有一个http状态代码来指示部分成功.响应对象是一个考虑因素,它可以使用户知道新的成功URL,并指出失败的URL(如果有)以及原因.随它或D.
解决方案C并非那么令人安心.您实际上并没有更新任何单一资源,对于消费者而言,这将是很难理解的.
解决方案D是B和C的合并.我希望在这里使用它,因为您实际上并没有更新完整的对象.您可以使用与B相同的网址
I have a basic Order
-OrderItem
situation and I'm struggling how to update Items in one request (or if should I?) Let me explain and I'm gonna ask the question at the end.
Models:
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; }
}
Use cases I want to cover:
- Add
Order
with lots ofOrderItems
- Update
Order
's properties, likeIsVoided
- Update
Order
's items (multiple items at once). Meaning - user will change multiple items in the UI and the request will be sent when pressed "Save". That includes, updating the current items, but also adding new items or removing items as well. Partial success shouldn't be allowed.
API's URIs to cover each use case:
- Add
Order
with lots ofOrderItems
:[POST] /api/orders/
with payload:
- Update
Order
's properties, likeIsVoided
(but NOT items):[PATCH] /api/orders/{orderId}
- Update
Order
's items (multiple items at once)
Here's the problem I'm having... I have a few ideas:
Solution A: Update Order's items one by one, so endpoints:
[POST] /api/orders/{orderId}/items
, with payload:{ "quantity": 25, "price": 50 }
[PUT] /api/orders/{orderId}/items/{itemId}
, with payload:{ "quantity": 25, "price": 50 }
[DELETE] /api/orders/{orderId}/items/{itemId}
Pros: Clean architecture. You Add/Update/Delete the actually Entity, using Entity's endpoint.
Cons: If user updates 500 items and click "Save", it will result in 500 requests to the server. Also, it will accept partial success
Solution B: Update Order's items at once by updating the Order: [PUT] /api/orders/{orderId}
with payload:
Pros: Performance, Partial success will not be allowed.
Cons: If user updates 50 items, deletes 50 and adds new 50 items to the order, in one request (a PUT
request on the Order
entitiy) we will esentially add, update, remove 50 items on a different entity - OrderItem
. I'm concerned if this is the good RESTful
practice.
Solution C: Update Order's items at once by updating... the collection: [PUT] /api/orders/{orderId}/items
with payload:
The collection in the payload, will completely replace the collection in the system, including Add and Remove operations.
Pros: Performance, Partial success will not be allowed, You don't mess with the parent Entity.
Cons: Is this a good practice to call PUT
request on a collection. Ususally when you have PUT
, the URI ends with some kinda ID (you're updating an entitiy). In this case, the URI will end with "items". Is this how it's done?
Solution D: A different solution, possibly with PATCH
? Never done that before, but maybe it's possible to send PATCH
for an Order
entity, patching the collection of Items. In JsonDocument's value, I would pass the collection of new items, items to remove and updated items?
So, my question is: Which of these solution is the best for this situation? A, B, C or (if exists)D? Or other solution I didn't think about?
Solution A is totally fine if you don't have many items. It does not suit your case as it makes your api chatty if you have many requests.
Solution B sends a lot at once. It adheres to the practice of updating with the full resource object and there is even an http status code to indicate partial success. Response object is a consideration to let the consumer know the new urls of successful and indicate the ones that failed if any and why. Go with it or D.
Solution C is not that restful. You are not really updating any single resource and it will be hard to understand for the consumers.
Solution D is a merge of B and C. I would expect it to be used here as you are not really updating the full object. You can use the same url as B
这篇关于如何在Web API中更新集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!