Restful way for deleting a bunch of items

Rest

Rest Problem Overview


In wiki article for REST it is indicated that if you use http://example.com/resources DELETE, that means you are deleting the entire collection.

If you use http://example.com/resources/7HOU57Y DELETE, that means you are deleting that element.

I am doing a WEBSITE, note NOT WEB SERVICE.

I have a list that has 1 checkbox for each item on the list. Once i select multiple items for deletion, i will allow users to press a button called DELETE SELECTION. If user presses the button, a js dialog box will popup asking user to confirm the deletion. if user confirms, all the items are deleted.

So how should i cater for deleting multiple items in a RESTFUL way?

NOTE, currently for DELETE in a webpage, what i do is i use FORM tag with POST as action but include a _method with the value DELETE since this is what was indicated by others in SO on how to do RESTful delete for webpage.

Rest Solutions


Solution 1 - Rest

One option is to create a delete "transaction". So you POST to something like http://example.com/resources/deletes a new resource consisting of a list of resources to be deleted. Then in your application you just do the delete. When you do the post you should return a location of your created transaction e.g., http://example.com/resources/deletes/DF4XY7. A GET on this could return the status of the transaction (complete or in progress) and/or a list of resources to be deleted.

Solution 2 - Rest

I think rojoca's answer is the best so far. A slight variation might be, to do away with the javascript confirm on the same page, and instead, create the selection and redirect to it, showing a confirm message on that page. In other words:

From:
http://example.com/resources/

do a

POST with a selection of the ID's to:
http://example.com/resources/selections

which, if successful, should respond with:

HTTP/1.1 201 created, and a Location header to:
http://example.com/resources/selections/DF4XY7

On this page you will then see a (javascript) confirm box, which if you confirm will do a request of:

DELETE http://example.com/resources/selections/DF4XY7

which, if successful, should respond with: HTTP/1.1 200 Ok (or whatever is appropriate for a successful delete)

Solution 3 - Rest

Here's what Amazon did with their S3 REST API.

Individual delete request:

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 request:

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>			

But Facebook Graph API, Parse Server REST API and Google Drive REST API go even further by enabling you to "batch" individual operations in one request.

Here's an example from Parse Server.

Individual delete request:

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

Batch request:

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

Solution 4 - Rest

Interestingly, i think the same method applies as to PATCHing multiple entities, and requires thinking about what we mean with our URL, parameters and REST method.

  1. return all 'foo' elements:

    [GET] api/foo

  2. return 'foo' elements with filtering for specific ids:

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

Wherein the sense is the URL and the filter determine "what elements we are dealing with?", and the REST method (in this case "GET") says "what to do with those elements?"

  1. Hence PATCH multiple records to mark them as read

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

..with the data foo[read]=1

  1. Finally to delete multiple records, this endpoint is most logical:

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

Please understand I don't believe there are any "rules" on this - to me it just "makes sense"

Solution 5 - Rest

I would say DELETE http://example.com/resources/id1,id2,id3,id4 or DELETE http://example.com/resources/id1+id2+id3+id4. As "REST is an architecture (...) [not] protocol" to quote this wikipedia article there is, I believe, no single one way of doing this.

I am aware that above is not possible without JS with HTML but I get the feeling that REST was:

  • Created without thinking of minor details like transactions. Who would need to operate on more then single item? This is somehow justified in HTTP protocol as it was not intended to serve through it anything else other then static webpages.
  • Not necessary well adjusting into current models - even of pure HTML.

Solution 6 - Rest

As Decent Dabbler answer and rojocas answer says, the most canonical is using virtual resources to delete a selection of resources, but I think that is incorrect from a REST perspective, because executing a DELETE http://example.com/resources/selections/DF4XY7 should remove the selection resource itself, not the selected resources.

Taking the Maciej Piechotka anwser or the fezfox answer, I only have an objection: There's a more canonical way of pass an array of ids, and is using the array operator:

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

In this way you are attacking to the Delete Collection endpoint but filtering the deletion with a querystring in the right way.

Solution 7 - Rest

As there is no 'proper' way to do this, what I have done in the past is:

send DELETE to http://example.com/something with xml or json encoded data in the body.

when you receive the request, check for DELETE, if true, then read the body for the ones to be deleted.

Solution 8 - Rest

I had the same situation to delete multiple items. This is what I ended up doing. I used DELETE operation and the ids of items which were to be deleted were part of HTTP header.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKim StacksView Question on Stackoverflow
Solution 1 - RestrojocaView Answer on Stackoverflow
Solution 2 - RestDecent DabblerView Answer on Stackoverflow
Solution 3 - RestLuka ŽitnikView Answer on Stackoverflow
Solution 4 - RestfezfoxView Answer on Stackoverflow
Solution 5 - RestMaciej PiechotkaView Answer on Stackoverflow
Solution 6 - RestmangelsncView Answer on Stackoverflow
Solution 7 - Restuser103219View Answer on Stackoverflow
Solution 8 - RestSherin SyriacView Answer on Stackoverflow