REST API - 在单个请求中批量创建或更新 [英] REST API - Bulk Create or Update in single request

查看:75
本文介绍了REST API - 在单个请求中批量创建或更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有两个资源 BinderDoc 具有关联关系意味着 DocBinder 代表他们自己.Doc 可能属于也可能不属于 Binder 并且 Binder 可能为空.

如果我想设计一个 REST API,允许用户发送 Doc 的集合,在单个请求中,如下所示:

<代码>{文档":[{"doc_number": 1, "binder": 1},{"doc_number": 5, "binder": 8},{"doc_number": 6, "binder": 3}]}

对于 docs 中的每个文档,

  • 如果 doc 存在,则将其分配给 Binder
  • 如果 doc 不存在,创建它然后分配它

我真的很困惑应该如何实施:

  • 使用什么 HTTP 方法?
  • 必须返回什么响应代码?
  • 这是否符合 REST 的要求?
  • URI 会是什么样子?/binders/docs?
  • 处理批量请求,如果有几个项目引发错误但另一个通过了怎么办.必须返回什么响应代码?批量操作应该是原子操作吗?

解决方案

我认为您可以使用 POST 或 PATCH 方法来处理此问题,因为它们通常为此而设计.

  • 使用 POST 方法 通常用于在列表资源上添加元素,但您也可以支持此方法的多种操作.请参阅此答案:以 REST 方式更新整个资源集合.您还可以支持输入的不同表示格式(如果它们对应于数组或单个元素).

    在这种情况下,没有必要定义您的格式来描述更新.

  • 使用PATCH方法也是合适的,因为相应的请求对应于部分更新.根据 RFC5789 (https://www.rfc-editor.org/rfc/rfc5789):

    <块引用>

    一些扩展超文本传输​​协议 (HTTP) 的应用程序需要一个功能来进行部分资源修改.现有的 HTTP PUT 方法只允许完全替换文档.该提案添加了一个新的 HTTP 方法 PATCH,用于修改现有的 HTTP 资源.

    在这种情况下,您必须定义格式来描述部分更新.

我认为在这种情况下,POSTPATCH 非常相似,因为您实际上不需要描述对每个元素执行的操作.我会说这取决于要发送的表示的格式.

PUT 的情况有点不太清楚.实际上,当使用方法PUT 时,您应该提供整个列表.事实上,请求中提供的表示将替换列表资源一.

关于资源路径,您可以有两个选项.

  • 使用文档列表的资源路径

在这种情况下,您需要在请求中提供的表示中明确提供带有活页夹的文档链接.

这是此 /docs 的示例路线.

这种方法的内容可以用于方法POST:

<预><代码>[{ "doc_number": 1, "binder": 4, (其他字段在创建的情况下) },{ "doc_number": 2, "binder": 4, (其他字段在创建的情况下) },{ "doc_number": 3, "binder": 5, (其他字段在创建的情况下) },(……)]

  • 使用活页夹元素的子资源路径

此外,您还可以考虑利用子路由来描述文档和绑定器之间的链接.现在不必在请求内容中指定有关文档和活页夹之间关联的提示.

这是此 /binder/{binderId}/docs 的示例路线.在这种情况下,使用 POSTPATCH 方法发送文档列表将在创建文档后将文档附加到具有标识符 binderId 的活页夹如果它不存在.

这种方法的内容可以用于方法POST:

<预><代码>[{ "doc_number": 1, (其他字段在创建的情况下) },{ "doc_number": 2, (其他字段在创建的情况下) },{ "doc_number": 3, (其他字段在创建的情况下) },(……)]

关于响应,您可以定义响应级别和要返回的错误.我看到两个级别:状态级别(全局级别)和有效负载级别(更薄级别).您还可以定义与您的请求相对应的所有插入/更新是否必须是原子的.

  • 原子

在这种情况下,您可以利用 HTTP 状态.如果一切顺利,您将获得状态 200.如果不是,如果提供的数据不正确(例如活页夹 ID 无效)或其他内容,则出现另一个状态,例如 400.

  • 非原子

在这种情况下,将返回状态 200 并且由响应表示来描述已完成的操作以及最终发生错误的位置.ElasticSearch 在其 REST API 中有一个用于批量更新的端点.这可以给你一些这个级别的想法:http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/bulk.html.

  • 异步

您还可以实现异步处理来处理提供的数据.在这种情况下,HTTP 状态返回将是 202.客户端需要拉一个额外的资源来看看会发生什么.

在完成之前,我还想注意到 OData 规范解决了具有名为导航链接的功能的实体之间的关系问题.也许你可以看看这个 ;-)

以下链接也可以帮助您:https://templth.wordpress.com/2014/12/15/designing-a-web-api/.

希望对你有帮助蒂埃里

Let's assume there are two resources Binder and Doc with association relationship meaning that the Doc and Binder stand on their own. Doc might or might not belong to Binder and Binder might be empty.

If I want to design a REST API that allows a user to send a collection of Docs, IN A SINGLE REQUEST, like the following:

{
  "docs": [
    {"doc_number": 1, "binder": 1}, 
    {"doc_number": 5, "binder": 8},
    {"doc_number": 6, "binder": 3}
  ]
}

And for each doc in the docs,

  • If the doc exists then assign it to Binder
  • If the doc doesn't exist, create it and then assign it

I'm really confused as to how this should be implemented:

  • What HTTP method to use?
  • What response code must be returned?
  • Is this even qualified for REST?
  • How would the URI look like? /binders/docs?
  • Handling bulk request, what if a few items raise an error but the other go through. What response code must be returned? Should the bulk operation be atomic?

解决方案

I think that you could use a POST or PATCH method to handle this since they typically design for this.

  • Using a POST method is typically used to add an element when used on list resource but you can also support several actions for this method. See this answer: Update an entire resource collection in a REST way. You can also support different representation formats for the input (if they correspond to an array or a single elements).

    In the case, it's not necessary to define your format to describe the update.

  • Using a PATCH method is also suitable since corresponding requests correspond to a partial update. According to RFC5789 (https://www.rfc-editor.org/rfc/rfc5789):

    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.

    In the case, you have to define your format to describe the partial update.

I think that in this case, POST and PATCH are quite similar since you don't really need to describe the operation to do for each element. I would say that it depends on the format of the representation to send.

The case of PUT is a bit less clear. In fact, when using a method PUT, you should provide the whole list. As a matter of fact, the provided representation in the request will be in replacement of the list resource one.

You can have two options regarding the resource paths.

  • Using the resource path for doc list

In this case, you need to explicitely provide the link of docs with a binder in the representation you provide in the request.

Here is a sample route for this /docs.

The content of such approach could be for method POST:

[
    { "doc_number": 1, "binder": 4, (other fields in the case of creation) },
    { "doc_number": 2, "binder": 4, (other fields in the case of creation) },
    { "doc_number": 3, "binder": 5, (other fields in the case of creation) },
    (...)
]

  • Using sub resource path of binder element

In addition you could also consider to leverage sub routes to describe the link between docs and binders. The hints regarding the association between a doc and a binder doesn't have now to be specified within the request content.

Here is a sample route for this /binder/{binderId}/docs. In this case, sending a list of docs with a method POST or PATCH will attach docs to the binder with identifier binderId after having created the doc if it doesn't exist.

The content of such approach could be for method POST:

[
    { "doc_number": 1, (other fields in the case of creation) },
    { "doc_number": 2, (other fields in the case of creation) },
    { "doc_number": 3, (other fields in the case of creation) },
    (...)
]

Regarding the response, it's up to you to define the level of response and the errors to return. I see two levels: the status level (global level) and the payload level (thinner level). It's also up to you to define if all the inserts / updates corresponding to your request must be atomic or not.

  • Atomic

In this case, you can leverage the HTTP status. If everything goes well, you get a status 200. If not, another status like 400 if the provided data aren't correct (for example binder id not valid) or something else.

  • Non atomic

In this case, a status 200 will be returned and it's up to the response representation to describe what was done and where errors eventually occur. ElasticSearch has an endpoint in its REST API for bulk update. This could give you some ideas at this level: http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/bulk.html.

  • Asynchronous

You can also implement an asynchronous processing to handle the provided data. In this case, the HTTP status returns will be 202. The client needs to pull an additional resource to see what happens.

Before finishing, I also would want to notice that the OData specification addresses the issue regarding relations between entities with the feature named navigation links. Perhaps could you have a look at this ;-)

The following link can also help you: https://templth.wordpress.com/2014/12/15/designing-a-web-api/.

Hope it helps you, Thierry

这篇关于REST API - 在单个请求中批量创建或更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆