删除一堆项目的宁静方法


97

REST的Wiki文章中 指出,如果使用http://example.com/resources DELETE,则意味着要删除整个集合。

如果您使用http://example.com/resources/7HOU57Y DELETE,则意味着您正在删除该元素。

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

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

那么我应该如何以一种RESTFUL的方式删除多个项目呢?

注意,当前对于网页中的DELETE,我要做的是我将FORM标记与POST一起使用,但包括一个_method,其值为DELETE,因为这是其他人在SO中如何进行RESTful删除网页的指示


1
以原子方式执行这些删除是否至关重要?如果第31个项目无法删除,您是否真的要撤消前30个项目的删除?
Darrel Miller'3

@darrelmiller好问题。我认为,如果删除操作是原子执行的,则效率会降低。因此,我倾向于从表名WHERE ID IN({list of ids})中删除。如果有人可以向我指出这是一个好主意还是纠正我。那将不胜感激。如果删除了第21个项目,我也不需要对前20个项目进行删除。同样,如果有人可以向我展示需要逆转和不需要逆转的方法之间的区别,我将不胜感激
Kim Stacks

1
注意:“ IN”子句可能有限制;例如,在Oracle中,您最多可以放置1000个ID。

Google的API设计指南提供了一种在REST API中创建自定义(批量)操作的解决方案,请在此处查看我的答案:stackoverflow.com/a/53264372/2477619
B12Toaster

Answers:


53

我认为rojoca的答案是迄今为止最好的。可能需要稍作更改,以消除同一页面上的javascript确认,而是创建选择并重定向到该选择,从而在该页面上显示一条确认消息。换一种说法:

来自:http :
//example.com/resources/

做一个

通过选择ID的POST到:http :
//example.com/resources/selections

如果成功,应以以下方式回应:

已创建HTTP / 1.1 201,并且位置标头位于:http :
//example.com/resources/selections/DF4XY7

然后,在此页面上,您将看到一个(javascript)确认框,如果您确认,将发出以下请求:

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

如果成功,则应使用以下命令响应:HTTP / 1.1 200 OK(或任何适合成功删除的条件)


我喜欢这个主意,因为您不需要任何重定向。结合AJAX,您无需离开页面就可以完成所有操作。
rojoca 2010年

这之后删除example.com/resources/selections/DF4XY7,我会被重定向到example.com/resources?
Kim Stacks 2010年

7
@fireeyeboy这两个步骤似乎是执行多次删除的一种常见建议方式,但是为什么呢?您为什么不简单地向URI发送DELETE请求,http://example.com/resources/selections/并且在请求的有效负载(正文)中向您发送希望删除其项目的数据。据我所知,没有什么可以阻止您执行此操作,但是我总是会遇到“但它不是RESTfull”的情况。
thecoshman 2013年

6
DELETE有可能已经身体无视HTTP基础设施:stackoverflow.com/questions/299628/...
卢克Puplett

DELETE可以具有主体,但是默认情况下,其许多实现都禁止其主体
dmitryvim

54

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


2
与您的数据库无关。事务是指要执行的操作的列表。在这种情况下,这是一个删除列表。您要做的是创建一个新列表(删除列表)作为应用程序中的资源。您的Web应用程序可以根据需要处理该列表。该资源具有URI,例如example.com/resources/deletes/DF4XY7。这意味着您可以通过该URI的GET检查删除状态。如果在执行删除操作时必须从Amazon S3或某些其他CDN删除图像,并且该操作可能需要很长时间才能完成,这将很方便。
rojoca 2010年

2
+1这是一个不错的解决方案。@rojoca提议创建一种新型资源的实例,而不是向每个资源发送DELETE,其唯一任务是删除资源列表。例如,您有一个用户资源集合,并且想要从集合中删除“用户Bob”,“ Dave”和“ Amy”,因此您创建了一个新的删除资源,将POST Bob,Dave和Amy作为创建参数。创建了“删除”资源,该资源表示从Users集合中删除Bob,Dave和Amy的异步过程。
Mike Tunnicliffe

1
对不起。我仍然很难理解一些问题。DF4XY7。您如何生成此字符串?此删除资源。我需要将任何数据插入数据库吗?如果我重复一些问题,我深表歉意。我只是有点不熟悉。
Kim Stacks 2010年

1
我假设DF4XY7是生成的唯一ID,也许更自然的是仅使用保存到数据库时生成的ID,例如example.com/resources/deletes/7。我的想法是创建删除模型并将其保存在数据库中,您可以让异步进程删除其他记录,以完成状态和任何相关错误更新删除模型。
Mike Tunnicliffe

2
@rojoca是的,我认为问题是HTTP非常“删除是用于删除单个资源”。无论您做什么,要进行多次删除都是有点麻烦。您仍然可以向客户端返回一个“作业”,表示正在执行此任务(可能需要一些时间),但可以使用此URI来检查进度。我阅读了规范,并认为DELETE可以具有主体,就像其他请求一样。
thecoshman

33

这就是亚马逊使用其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))

多对象删除请求:

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

13

我会说DELETE http://example.com/resources/id1、id2、id3、id4或Delete http://example.com/resources/id1+id2+id3+id4。我相信,引用此Wikipedia文章的方式是“ REST是一种体系结构(...)[不是]协议”,因此,没有任何一种方法可以做到这一点。

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

  • 无需考虑交易等次要细节即可创建。谁需要处理更多而不是单个项目?这在HTTP协议中以某种方式是合理的,因为它不打算通过静态网页提供其他服务。
  • 没有必要很好地适应当前模型-即使是纯HTML。

thx-如果您想删除整个集合,该怎么办?应该省略ID吗?
BKSpurgeon

“我感觉到REST是……在创建时没有考虑事务之类的细微细节的” –我认为这不是真的。如果我正确理解,在REST中,事务是由资源而不是方法表示的。在此博客文章中的评论中,有一些很好的讨论而达到高潮。
Paul D. Waite

10

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

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

    [GET] api/foo

  2. 返回带有过滤特定ID的'foo'元素:

    [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。
SzabolcsPáll2015年

2

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

采取Maciej Piechotka anwserfezfox答案,我只有一个反对意见:还有一种更规范的方法来传递id数组,并且正在使用array运算符:

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

这样,您攻击的是Delete Collection端点,但以正确的方式使用查询字符串过滤了删除内容。


-1

由于没有做到这一点的“适当”方法,因此我过去所做的是:

将正文中带有xml或json编码数据的DELETE发送到http://example.com/something

收到请求时,请检查DELETE(如果为true),然后读取要删除的内容的正文。


这对我来说很有意义,您只需要在一个请求中发送数据,但是我总是会遇到“但不是RESTfull”的情况。您是否有任何来源表明这是可行的“ RESTfull”方法?
thecoshman 2013年

10
这种方法的问题在于,DELETE操作不希望有主体,因此,Internet上的某些中间路由器可能会在您不知情的情况下为您将其删除。因此,将主体用于DELETE是不安全的!
亚历克斯·怀特


1
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
cottton 2016年

-1

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.