【问题标题】:How to Design a Restful API for Bulk Inserts and Updates?如何为批量插入和更新设计一个 Restful API?
【发布时间】:2013-06-21 23:22:33
【问题描述】:

我有一个 Web API 应用程序,我使用下面的 url 进行批量(数十或数百)插入和更新,返回 OK 或 Failed。

POST api/v1/products

映射到我的操作:

public HttpResponseMessage PostProducts(PostProductsRequest request)
{

...
}

PostProductsRequest 对象包含 List 类型的 Products 属性。

如果某个属性的 Id 属性存在,我会更新它,否则它会指示插入。

但我只是想知道是否应该将 Post 用于批量插入,而将 Put 用于批量更新,不确定。每种方法的最佳做法和优势是什么?

如何为批量插入和更新设计一个 Restful API?

【问题讨论】:

  • 我的第一个想法是:如果它有效,请不要修复它PUTPOST 之间的差异太小,无法在这里产生影响。
  • 这通常是正确的,但 POST 和 PUT 表示不同的意图。您可以根据需要多次调用 PUT,但只能为项目执行一次 POST。

标签: c# asp.net rest asp.net-web-api


【解决方案1】:

可以使用任何一种方法,具体取决于您的要求,但这并不意味着它们没有显着差异。 HTTP 方法不是 CRUD。 PUT 或 POST 不是创建和更新,或者相反。

PUT 完全 将给定 URI 处的资源替换为提供的实体,因此它可以用于创建和更新,但前提是它包含完整表示。在 PUT 之后立即发出的 GET 请求应该返回相同的资源。表示可能完全相同,尽管服务可以添加 PUT 表示中缺少的默认值。

POST 告诉服务器所提供的实体从属于给定 URI 的资源,并且他们就应该如何处理达成一致。它可能是任何东西,一个创建、一个更新、任何 HTTP 本身没有标准化的操作。

考虑到这一点,仅当您要替换由 URI 标识的整个集合时,使用 PUT 进行的批量插入或更新才是 RESTful。这不一定是与该媒体类型关联的整个集合。 URI 可以有一个对数据集进行切片的查询字符串,并且您只能在该切片上执行批量操作。

例如,如果您有以下收藏资源:

GET /api/products

代表:

{'products': [product1, product2, product3]}

如果您想再添加三个产品,使用 PUT 的批量操作必须将您的新产品附加到现有产品并将整个集合发回:

PUT /api/products

{'products': [product1, product2, product3, product4, product5, product6]}

但是,如果您有一个过滤器约束,您可以应用到/api/products,这将在上面的 GET 上返回一个空集合,那么只对该过滤资源的新产品执行 PUT 就可以了。例如,假设上面的产品可以按合作伙伴属性过滤,它们有合作伙伴 x,而您正在为合作伙伴 y 添加:

在这种情况下,你可以这样做:

PUT /api/products?partner=y

{'products': [product4, product5, product6]}

然后返回一个GET /api/products

{'products': [product1, product2, product3, product4, product5, product6]}

只要GET /api/products?partner=x返回:

{'products': [product1, product2, product3]}

然后GET /api/products?partner=y 返回:

{'products': [product4, product5, product6]}

这可能看起来很复杂,有时看起来最好使用 POST 而不是 PUT,但请记住,上面的整个操作都是标准化的。它完全按照预期使用 PUT。使用 POST 可以更直接地进行操作,但它们不是标准化的,您必须为其设计和记录自己的语法。

【讨论】:

    【解决方案2】:

    我建议使用POST 来创建和PUT 来更新(实际上是indempotent 来创建或更新)。

    来自RESTful Webservices Cookbook(奥莱利):

    使用 POST 和集合资源一次创建多个类似资源。 让 客户端在请求中包含有关要创建的资源的信息。分配一个 创建的所有资源的 URI,并使用响应将客户端重定向到集合 代码 303(见其他)。此资源的表示包括指向所有新 创建资源。

    要批量更新或删除大量类似资源,请使用单个 URI,该 URI 可以 返回包含有关所有这些资源的信息的表示。提交一份 向该 URI 发出 PUT 请求,其中包含有关要更新的资源的信息或 DELETE 请求删除这些资源。 在所有这些情况下,请确保请求的处理是原子的。

    【讨论】:

    • 如果资源标识符是 Guid 怎么办?因此,将 guid 列表放入请求 url 看起来不太好。
    【解决方案3】:

    我刚好在看HTTP 1.1 method definition,被提醒了这个问题。

    PUT 方法请求将封闭的实体存储在提供的 Request-URI 下。如果 Request-URI 引用一个已经存在的资源,封闭的实体应该被认为是源服务器上的一个修改版本。 如果 Request-URI 不指向现有资源,并且该 URI 能够被请求用户代理定义为新资源,则源服务器可以使用该 URI 创建资源。

    这将向我表明,如果您要使用 PUT 并且有效负载包含一个不存在的资源,该资源具有足够的信息来创建它,那么应该创建它,因此 PUT 将是可以创建的批量操作中的正确方法动词并更新资源。

    【讨论】:

      【解决方案4】:

      对于 RESTful Web 服务中的批处理操作,最“符合标准”的方式是使用各种“收集”方法之一(即DELETE /mail?&id=0&id=1&id=2),或者您可以使用batching handler 来简化流程。

      老实说,我使用与您完全相同的模式,除了我使用POST 来创建对象和PUT 仅用于更新(这是执行此操作的标准方式)。如果操作成功,POST 应该返回 201 - Created 以及创建的对象,PUT 应该返回没有数据的 204 - No Content。当然,当您进行批量创建时,您可以选择不返回带有POST 的新创建对象数组。

      总结一下:

      POST api/products
        |
        |---> Success: 201 [NewObject1, NewObject2, ...]
        |---> Failure: Relevant error code as to why the operation failed
      
      PUT api/products
        |
        |---> Success: 204
        |---> Failure: Relevant error code as to why the operation failed
      

      更新:ASP.NET Web API 的 vNext 将有 batching built in!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-03
        • 2021-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-16
        • 2012-02-16
        • 1970-01-01
        相关资源
        最近更新 更多