I need to delete multiple items by id in the batch however HTTP DELETE does not support a body payload.
Work around options:
1. @DELETE /path/abc?itemId=1&itemId=2&itemId=3 on the server side it will be parsed as List of ids and DELETE operation will be performed on each item.
2. @POST /path/abc including JSON payload containing all ids. { ids: [1, 2, 3] }
How bad this is and which option is preferable? Any alternatives?
Update: Please note that performance is a key here, it is not an option execute delete operation for each individual id.
Along the years, many people fell in doubt about it, as we can see in the related questions here aside. It seems that the accepted answers ranges from "for sure do it" to "its clearly mistreating the protocol". Since many questions was sent years ago, let's dig into the HTTP 1.1 specification from June 2014 (RFC 7231), for better understanding of what's clearly discouraged or not.
The first proposed workaround:
First, about resources and the URI itself on Section 2:
Based on it, some may argue that since HTTP does not limite the nature of a resource, a URI containing more than one
id
would be possible. I personally believe it's a matter of interpretation here.About your first proposed workaround (
DELETE '/path/abc?itemId=1&itemId=2&itemId=3'
) we can conclude that it's something discouraged if you think about a resource as a single document in your entity collection while being good to go if you think about a resource as the entity collection itself.The second proposed workaround:
About your second proposed workaround (
POST '/path/abc' with body: { ids: [1, 2, 3] }
), usingPOST
method for deletion could be misleading. The section Section 4.3.3 says aboutPOST
:While there's some space for interpretation about "among others" functions for
POST
, it clearly conflicts with the fact that we have the methodDELETE
for resources removal, as we can see in Section 4.1:So I personally strongly discourage the use of
POST
to delete resources.An alternative workaround:
Inspired on your second workaround, we'd suggest one more:
It's almost the same as proposed in the workaround two but instead using the correct HTTP method for deletion. Here, we arrive to the confusion about using an entity
body
in aDELETE
request. There are many people out there stating that it isn't valid, but let's stick with the Section 4.3.5 of the specification:So, we can conclude that the specification doesn't prevent
DELETE
from having abody
payload. Unfortunately some existing implementations could reject the request... But how is this affecting us today?It's hard to be 100% sure, but a modern request made with
fetch
just doesn't allowbody
forGET
andHEAD
. It's what the Fetch Standard states at Section 5.3 on Item 34:And we can confirm it's implemented in the same way for the fetch pollyfill at line 342.
Final toughts:
Since the alternative workaround with
DELETE
and abody
payload is let viable by the HTTP specification and is supported by all modern browsers withfetch
and since IE10 with the polyfill, I recommend this way to do batch deletes in a valid and full working way.It's important to understand that the HTTP methods operate in the domain of "transferring documents across a network", and not in your own custom domain.
Your resource model is not your domain model is not your data model.
Alternative spelling: the REST API is a facade to make your domain look like a web site.
Behind the facade, the implementation can do what it likes, subject to the consideration that if the implementation does not comply with the semantics described by the messages, then it (and not the client) are responsible for any damages caused by the discrepancy.
So that HTTP request says specifically "Apply the delete semantics to the document described by
/path/abc?itemId=1&itemId=2&itemId=3
". The fact that this document is a composite of three different items in your durable store, that each need to be removed independently, is an implementation details. Part of the point of REST is that clients are insulated from precisely this sort of knowledge.However, and I feel like this is where many people get lost, the metadata returned by the response to that delete request tells the client nothing about resources with different identifiers.
As far as the client is concerned,
/path/abc
is a distinct identifier from/path/abc?itemId=1&itemId=2&itemId=3
. So if the client did a GET of /path/abc, and received a representation that includes itemIds 1, 2, 3; and then submits the delete you describe, it will still have within its own cache the representation that includes/path/abc
after the delete succeeds.This may, or may not, be what you want. If you are doing REST (via HTTP), it's the sort of thing you ought to be thinking about in your design.
This method tells the client that we are making some (possibly unsafe) change to
/path/abc
, and if it succeeds then the previous representation needs to be invalidated. The client should repeat its earlierGET /path/abc
request to refresh its prior representation rather than using any earlier invalidated copy.But as before, it doesn't affect the cached copies of other resources
All of these are still going to be sitting there in the cache, even though they have been "deleted".
To be completely fair, a lot of people don't care, because they aren't thinking about clients caching the data they get from the web server. And you can add metadata to the responses sent by the web server to communicate to the client (and intermediate components) that the representations don't support caching, or that the results can be cached but they must be revalidated with each use.
Again: Your resource model is not your domain model is not your data model. A REST API is a different way of thinking about what's going on, and the REST architectural style is tuned to solve a particular problem, and therefore may not be a good fit for the simpler problem you are trying to solve.