【问题标题】:Restful way for deleting a bunch of items删除一堆项目的宁静方式
【发布时间】:2011-01-26 04:02:22
【问题描述】:

wiki article for REST 表示如果您使用http://example.com/resourcesDELETE,则表示您正在删除整个集合。

如果您使用http://example.com/resources/7HOU57YDELETE,则表示您正在删除该元素。

我正在做一个网站,注意不是网络服务。

我有一个列表,列表中的每个项目都有 1 个复选框。一旦我选择了多个要删除的项目,我将允许用户按下一个名为 DELETE SELECTION 的按钮。如果用户按下按钮,会弹出一个 js 对话框,要求用户确认删除。如果用户确认,则删除所有项目。

那么我应该如何满足以 RESTFUL 方式删除多个项目?

注意,目前对于网页中的 DELETE,我所做的是我使用 FORM 标记和 POST 作为操作,但包含一个 _method,其值为 DELETE,因为this is what was indicated by others in SO on how to do RESTful delete for webpage

【问题讨论】:

  • 以原子方式执行这些删除是否至关重要?如果第 31 条不能删除,你真的要撤销前 30 条的删除吗?
  • @darrelmiller 好问题。我认为如果以原子方式执行删除,效率会降低。因此,我倾向于从表名 WHERE ID IN ({list of ids}) 中删除。如果有人可以向我指出这是一个好主意还是纠正我。那将不胜感激。如果第 21 项被删除,我也不需要前 20 项的反向删除。如果有人可以向我展示我需要反转的方法与我不需要反转的方法的区别,我再次感激不尽
  • 注意:“IN”子句可能有限制;例如,在 Oracle 中,您最多可以放置 1000 个 id。
  • Google 的 API 设计指南提供了一种在 REST API 中创建自定义(批处理)操作的解决方案,请在此处查看我的答案:stackoverflow.com/a/53264372/2477619

标签: rest


【解决方案1】:

我认为rojoca's answer 是迄今为止最好的。一个细微的变化可能是,取消同一页面上的 javascript 确认,而是创建选择并重定向到它,在该页面上显示确认消息。换句话说:

发件人:
http://example.com/resources/

做一个

选择 ID 后发送至:
http://example.com/resources/selections

如果成功,应该回复:

已创建 HTTP/1.1 201,并将 Location 标头发送到:
http://example.com/resources/selections/DF4XY7

在此页面上,您将看到一个 (javascript) 确认框,如果您确认,它将执行以下请求:

删除http://example.com/resources/selections/DF4XY7

如果成功,应该回复: HTTP/1.1 200 Ok(或任何适合成功删除的内容)

【讨论】:

  • 我喜欢这个想法,因为您不需要任何重定向。结合 AJAX,您可以在不离开页面的情况下完成这一切。
  • 删除example.com/resources/selections/DF4XY7后,我会被重定向回example.com/resources吗?
  • @fireeyeboy 这种两步方法似乎是执行多重删除的常用建议方式,但为什么呢?您为什么不简单地向 http://example.com/resources/selections/ 之类的 uri 发送 DELETE 请求,并在请求的有效负载(正文)中发送您希望删除的项目的数据。据我所知,没有什么能阻止你这样做,但我总是遇到“但它不是 RESTfull”。
  • DELETE 可能会使正文被 HTTP 基础设施忽略:stackoverflow.com/questions/299628/…
  • DELETE 可以有一个主体,但是它的很多实现默认禁止它的主体
【解决方案2】:

一种选择是创建删除“事务”。所以你 POSThttp://example.com/resources/deletes 这样的新资源,其中包含要删除的资源列表。然后在您的应用程序中,您只需执行删除。当您发布帖子时,您应该返回您创建的交易的位置,例如http://example.com/resources/deletes/DF4XY7。对此的GET 可以返回事务的状态(完成或正在进行)和/或要删除的资源列表。

【讨论】:

  • 与您的数据库无关。事务我只是指要执行的操作列表。在这种情况下,它是一个删除列表。您所做的是在应用程序中创建一个新列表(删除列表)作为资源。您的 Web 应用程序可以根据需要处理该列表。该资源有一个 URI,例如 example.com/resources/deletes/DF4XY7。这意味着您可以通过对该 URI 的 GET 来检查删除的状态。如果您在执行删除操作时必须从 Amazon S3 或其他一些 CDN 中删除图像并且该操作可能需要很长时间才能完成,这将非常方便。
  • +1 这是一个不错的解决方案。 @rojoca 建议创建一种新型资源的实例,其唯一任务是删除资源列表,而不是向每个资源发送 DELETE。例如,您有一个用户资源集合,并且想要从集合中删除用户 Bob、Dave 和 Amy,因此您创建了一个新的删除资源,将 Bob、Dave 和 Amy 作为创建参数发布。创建删除资源,并表示从用户集合中删除 Bob、Dave 和 Amy 的异步过程。
  • 对不起。我在理解一些问题上仍然有些困难。 DF4XY7。你到底是怎么生成这个字符串的?此删除资源。我需要在数据库中插入任何数据吗?如果我重复一些问题,我深表歉意。对我来说只是有点陌生​​。
  • 我假设 DF4XY7 是生成的唯一 id,也许只使用保存到数据库时生成的 id 更自然,例如 example.com/resources/deletes/7。我的想法是创建删除模型并将其保存在数据库中,您可以让异步过程删除其他记录以完成状态和任何相关错误更新删除模型。
  • @rojoca 是的,我认为问题在于 HTTP 非常“删除用于删除单个资源”。无论您做什么,多次删除都有点麻烦。您仍然可以向客户端返回一个“工作”,说明此任务正在处理(可能需要一些时间),但使用此 URI 来检查进度。我阅读了规范并认为 DELETE 可以有一个主体,就像其他请求一样。
【解决方案3】:

这是 Amazon 使用 S3 REST API 所做的。

个别删除请求:

DELETE /ObjectName HTTP/1.1
Host: BucketName.s3.amazonaws.com
Date: date
Content-Length: length
Authorization: authorization string (see Authenticating Requests (AWS Signature Version 4))

Multi-Object Delete 请求:

POST /?delete HTTP/1.1
Host: bucketname.s3.amazonaws.com
Authorization: authorization string
Content-Length: Size
Content-MD5: MD5

<?xml version="1.0" encoding="UTF-8"?>
<Delete>
    <Quiet>true</Quiet>
    <Object>
         <Key>Key</Key>
         <VersionId>VersionId</VersionId>
    </Object>
    <Object>
         <Key>Key</Key>
    </Object>
    ...
</Delete>           

Facebook Graph APIParse Server REST APIGoogle Drive REST API 更进一步,让您能够在一个请求中“批处理”单个操作。

这是 Parse Server 的一个示例。

个别删除请求:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm

批量请求:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "requests": [
          {
            "method": "POST",
            "path": "/1/classes/GameScore",
            "body": {
              "score": 1337,
              "playerName": "Sean Plott"
            }
          },
          {
            "method": "POST",
            "path": "/1/classes/GameScore",
            "body": {
              "score": 1338,
              "playerName": "ZeroCool"
            }
          }
        ]
      }' \
  https://api.parse.com/1/batch

【讨论】:

    【解决方案4】:

    有趣的是,我认为相同的方法适用于修补多个实体,并且需要考虑我们对 URL、参数和 REST 方法的含义。

    1. 返回所有 'foo' 元素:

      [GET] api/foo

    2. 返回 'foo' 元素并过滤特定 ID:

      [GET] api/foo?ids=3,5,9

    什么意思是 URL 和过滤器确定“我们正在处理哪些元素?”,而 REST 方法(在本例中为“GET”)表示“如何处理这些元素?”

    1. 因此 PATCH 多条记录以将它们标记为已读

      [PATCH] api/foo?ids=3,5,9

    ..with 数据 foo[read]=1

    1. 最后要删除多条记录,这个端点是最合乎逻辑的:

      [DELETE] api/foo?ids=3,5,9

    请理解我不相信这有任何“规则” - 对我来说它只是“有意义”

    【讨论】:

    • 实际上关于 PATCH: 因为如果您将实体列表视为实体本身(即使是数组类型),它意味着部分更新,发送部分数组(只有您想要更新的 id)部分实体,然后您可以省略查询字符串,因此没有代表多个实体的 URL。
    • 确实,只是简单的解决方案。为什么人们必须坚持让自己变得困难,有时我无法理解。
    【解决方案5】:

    我会说删除http://example.com/resources/id1,id2,id3,id4 或删除http://example.com/resources/id1+id2+id3+id4。由于“REST 是一种架构(...)[不是]协议”引用这篇维基百科文章,我相信没有单一的方法可以做到这一点。

    我知道如果没有带有 HTML 的 JS,以上是不可能的,但我觉得 REST 是:

    • 创建时没有考虑交易等次要细节。谁需要对单个项目进行操作?这在 HTTP 协议中是合理的,因为它不打算通过它提供除静态网页之外的任何其他内容。
    • 没有必要很好地适应当前模型 - 即使是纯 HTML。

    【讨论】:

    • thx - 如果你想删除整个集合怎么办 - 应该省略 ID 吗?
    • “我感觉 REST 是......创建时没有考虑事务等小细节”——我认为这不太正确。如果我理解正确,在 REST 中,事务是由资源表示的,而不是由方法表示的。有一些很好的讨论以this comment on this blog post 告终。
    【解决方案6】:

    正如Decent Dabbler answerrojocas answer 所说,最规范的是使用虚拟资源来删除资源选择,但我认为从 REST 角度来看这是不正确的,因为执行 DELETE http://example.com/resources/selections/DF4XY7 应该删除选择资源本身,而不是选定的资源。

    Maciej Piechotka anwserfezfox answer 为例,我只有一个反对意见:有一种更规范的方式来传递一个id 数组,并且是使用数组运算符:

    DELETE /api/resources?ids[]=1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d&amp;ids[]=7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b

    通过这种方式,您正在攻击删除集合端点,但以正确的方式使用查询字符串过滤删除。

    【讨论】:

      【解决方案7】:

      由于没有“正确”的方法来做到这一点,我过去所做的是:

      将 DELETE 发送到 http://example.com/something,正文中包含 xml 或 json 编码数据。

      当您收到请求时,请检查 DELETE,如果为 true,则阅读正文以查找要删除的内容。

      【讨论】:

      • 这对我来说是有意义的方法,您只需在一个请求中发送数据,但我总是遇到“但它不是 RESTfull”。您是否有任何消息来源表明这是一种可行的“RESTfull”方法?
      • 这种方法的问题是 DELETE 操作不需要一个 body,因此 Internet 上的一些中间路由器可能会在您无法控制或不知情的情况下为您删除它。所以使用 body 进行 DELETE 是不安全的!
      • A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request. 来自tools.ietf.org/html/rfc7231#section-4.3.5
      【解决方案8】:

      我有同样的情况删除多个项目。这就是我最终做的。我使用了 DELETE 操作,要删除的项目的 ID 是 HTTP 标头的一部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-02
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-24
        相关资源
        最近更新 更多