REST delete multiple items in the batch - rest

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:
The target of an HTTP request is called a "resource". HTTP does not limit the nature of a resource; it merely defines an interface that might be used to interact with resources. Each resource is identified by a Uniform Resource Identifier (URI).
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] }), using POST method for deletion could be misleading. The section Section 4.3.3 says about POST:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others): Providing a block of data, such as the fields entered into an HTML form, to a data-handling process; Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles; Creating a new resource that has yet to be identified by the origin server; and Appending data to a resource's existing representation(s).
While there's some space for interpretation about "among others" functions for POST, it clearly conflicts with the fact that we have the method DELETE for resources removal, as we can see in Section 4.1:
The DELETE method removes all current representations of the target resource.
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:
DELETE '/path/abc' with body: { ids: [1, 2, 3] }
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 a DELETE 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:
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.
So, we can conclude that the specification doesn't prevent DELETE from having a body 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 allow body for GET and HEAD. It's what the Fetch Standard states at Section 5.3 on Item 34:
If either body exists and is non-null or inputBody is non-null, and request’s method is GET or HEAD, then throw a TypeError.
And we can confirm it's implemented in the same way for the fetch pollyfill at line 342.
Final thoughts:
Since the alternative workaround with DELETE and a body payload is let viable by the HTTP specification and is supported by all modern browsers with fetch 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.
DELETE /path/abc?itemId=1&itemId=2&itemId=3
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.
POST /path/abc
some-useful-payload
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 earlier GET /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
/path/abc/1
/path/abc/2
/path/abc/3
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.
That doesn’t mean that I think everyone should design their own systems according to the REST architectural style. REST is intended for long-lived network-based applications that span multiple organizations. If you don’t see a need for the constraints, then don’t use them. That’s fine with me as long as you don’t call the result a REST API. I have no problem with systems that are true to their own architectural style. -- Fielding, 2008

Related

REST API: Does validation on identifiers break encapsulation? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 months ago.
Improve this question
I figured I'd post here to get some ideas/feedback on something I've come up against recently. The API I've developed has validation on an identifier that's passed through as a path parameter:
e.g. /resource/resource_identifier
There are some specific business rules as to what makes an idenfier valid and my API has validation which enforces these rules and returns a 400 when that's violated.
Now the reason I'm writing this is that I've been doing this sort of thing in every REST (ish) API I've ever written. It's kind of ingrained in me now but ecently I've been told that this is 'bad' and that it breaks encapsulation. Furthermore, it does this by forcing a consumer to have knowledge about the format of an identifier. I'm told that I should be returning a 404 instead and simply accept anything as an idenfier.
We've had some pretty heated debates about this and what encapsulation actually means in the context of REST. I've found numerous definitions but they aren't specific. As with any REST contention it's hard to substantiate an argument for either.
If StackOverflow would allow me, I'd like to try and gain a concensus on this and why APIs like Spotify for example, use 400 in this scenario.
I've been doing this sort of thing in every REST (ish) API I've ever written. It's kind of ingrained in me now but recently I've been told that this is 'bad'
In the context of HTTP, it is an "anti-pattern", yes.
I'm told that I should be returning a 404 instead
And that is the right pattern when you want the advantages of responding like a general purpose web server.
Here's the point: if you want general purpose components in the HTTP application to be able to do sensible things with your response messages, then you need to provide them with the appropriate meta data.
In the case of a target resource identifier that satisfies the request-target production rules defined in RFC 9112 but is otherwise unsatisfactory; you can choose any response semantics you want (400? 403? 404? 499? 200?).
But if you choose 404, then general purpose components will know that the response is an error that can be re-used for other requests (under appropriate conditions - see RFC 9111).
why APIs like Spotify for example, use 400 in this scenario.
Remember: engineering is about trade offs.
The benefits of caching may not outweigh more cost effective request processing, or more efficient incident analysis, or ....
It's also possible that it's just habit - it's done that way because that's the way that they have always done it; or because they were taught it as a "best practice", or whatever. One of the engineering trade offs we need to consider is whether or not to invest in analyzing a trade off!
An imperfect system that ships earns more market share than a perfect solution that doesn't.
While it may sound natural to expose the resource internal ID as ID used in the URI, remember that the whole URI itself is the identifier of a resource and not only the last bit of the URI. Clients are usually also not interested in the characters that form the URI (or at least they shouldn't care about it) but only in the state they receive upon requesting that from the API/server.
Further, if you think long-term, which should be the reason why you want to build your design on top of a REST architecture, is there a chance that the internal identifier of a resource could ever change? If so, introducing an indirection could make more sense then i.e. by using UUIDs instead of product IDs in the URI and then have a further table/collection to perform a mapping from UUID to domain object ID. Think of a resource that exposes some data of a product. It may sound like a good idea to use the product ID at the end of the URI as they identify the product in your domain model clearly. But what happens if you company undergoes a merge with an other company that happens to have an overlap on product but then uses different identifiers than you? I've seen such cases in reality, unfortunately, and almost all of them wanted to avoid change for their clients and so had to support multiple URIs for the same products in the end.
This is exactly why Mike Amundsen said
... your data model is not your object model is not your resource model ... (Source)
REST is full of such indirection mechanisms to allow such systems to avoid coupling. I.e. besides above mentioned mechanism, you also have link-relations to allow servers to switch URIs when needed while clients can still lookup the URI via the exposed relation name, or its focus on negotiated media types and its representation formats rather than forcing clients to speak their API-specific RPC-like, plain-JSON slang.
Jim Webber further coined the term domain application protocol to describe that HTTP is an application protocol for exchanging documents and any business rules we infer are just side effects of the actual document management performed by HTTP. So all we do in "REST" is basically to send documents back and forth and infer some business logic to act upon receiving certain documents.
In regards to encapsulation, this isn't the scope of REST nor HTTP. What data you return depends on your business needs and/or on the capabilities of the representation formats exchanged. If a certain media-type isn't able to express a certain capability, providing such data to clients might not make much sense.
In general, I'd would recommend not to use domain internal IDs as part of URIs for the above mentioned reasons. Usually that information should be part of the exchanged payload to give users/customers the option to refer to that resources on other channels like e/mail, telephone, ... Of course, that depends on the resource and its purpose at hand. As a user I'd prefer to refer to myself with my full name rather than some internal user- or customer ID or the like.
edit: sorry, missed the validation aspect ...
If you expect user/client input on the server/API side, you should always validate the data before starting to process it. Usually though, URIs are provided by the server and might only trigger business activities if the URI requested matches one of your defined rules. In general, most frameworks will respond with 400 Bad Request responses when they couldn't map the URI to a concrete action, giving the client a chance to correct its mistake and reissue the updated request. As URIs shouldn't be generated or altered by clients anyways, validating such parameters might be unnecessary overhead unless they might introduce security risks. Here it might be a better approach then to toughen-up the mapping rules of URIs to actions then and let those frameworks respond with a 400 message when clients use stuff they aren't supposed to.
Encapsulation makes sense when we want to hide data and implementation behind an interface. Here we want to expose the structure of the data, because it is for communication, not for storage and the service certainly needs this communication in order to function. Validation of data is a very basic concept, because it makes the service reliable and because is protects against hacking attempts. The id here is a parameter and checking its structure is just parameter validation, which should return 400 if failed. So this is not restricted to the body of the request, the problem can be anywhere in the HTTP message as you can read below. Another argument against 404 that the requested resource cannot possibly exist, because we are talking about a malformed id and so a malformed URI. It is very important to validate every user input, because a malformed parameter can be used for injections e.g. for SQL injection if it is not validated.
The HyperText Transfer Protocol (HTTP) 400 Bad Request response status
code indicates that the server cannot or will not process the request
due to something that is perceived to be a client error (for example,
malformed request syntax, invalid request message framing, or
deceptive request routing).
vs
The HTTP 404 Not Found response status code indicates that the server
cannot find the requested resource. Links that lead to a 404 page are
often called broken or dead links and can be subject to link rot.
A 404 status code only indicates that the resource is missing: not
whether the absence is temporary or permanent. If a resource is
permanently removed, use the 410 (Gone) status instead.
In the case of REST we describe the interface using the HTTP protocol, URI standard, MIME types, etc. instead of the actual programming language, because they are language independent standards. As of your specific case it would be nice to check the uniform interface constraints including the HATEOAS constraint, because if your service makes the URIs as it should, then it is clear that a malformed id is something malicious. As of Spotify and other APIs, 99% of them are not REST APIs, maybe REST-ish. Read the Fielding dissertation and standards instead of trying to figure it out based on SO answers and examples. So this a classic RTFM situation.
In the context of REST a very simple example of data hiding is storing a number something like:
PUT /x {"value": "111"} "content-type:application/vnd.example.binary+json"
GET /x "accept:application/vnd.example.decimal+json" -> {"value": 7}
Here we don't expose how we store the data. We just send the binary and decimal representations of it. This is called data hiding. In the case of id it does not make sense to have an external id and convert it to an internal id, it is why you use the same in your database, but it is fine to check if its structure is valid. Normally you validate it and convert it into a DTO.
Implementation hiding is more complicated in this context, it is sort of avoiding micromanagement with the service and rather implement new features if it happens frequently. It might involve consumer surveys about what features they need and checking logs and figuring out why certain consumers send way too many messages and how to merge them into a single one. For example we have a math service:
PUT /x 7
PUT /y 8
PUT /z 9
PUT /s 0
PATCH /s {"add": "x"}
PATCH /s {"add": "y"}
PATCH /s {"add": "z"}
GET /s -> 24
vs
POST /expression {"sum": [7,8,9]} -> 24
If you want to translate between structured programming, OOP and REST, then it is something like this:
Number countCartTotal(CartId cartId);
<=>
interface iCart {
Number countTotal();
}
<=>
GET api/cart/{cartid}/total -> {total}
So an endpoint represents an exposed operation something like verbNoun(details) e.g. countCartTotal(cartId), which you can split into verb=countTotal, noun=cart, details=cartId and build the URI from it. The verb must be transformed into a HTTP method. In this case using GET makes the most sense, because we need data instead of sending data. The rest of the verb must be transformed into a noun, so countTotal -> GET totalCount. Then you can merge the two nouns: totalCount + cart -> cartTotal. Then you can build an URI template based on the resulting noun and the details: cartTotal + cartId -> cart/{cartid}/total and you are done with the endpoint design GET {root}/cart/{cartid}/total. Now you can bind it to the countCartTotal(cartId) or to the repo.resource(iCart, cartId).countTotal().
So I think if the structure of the id does not change, then you can even add it to the API documentation if you want to. Though it is not necessary to do so.
From security perspective you can return 404 if the only possible reason to send such a request is a hacking attempt, so the hacker won't know for certain why it failed and you don't expose details of the protection. In this situation it would be overthinking the problem, but in certain scenarios it makes sense e.g. where the API can leak data. For example when you send a password reset link, then a web application usually asks for an email address and most of them send an error message if it is not registered. This can be used to check if somebody is registered on the site, so better to hide this kind of errors. I guess in your case the id is not something sensitive and if you have proper access control, then even if a hacker knows the id, they cannot do much with that information.
Another possible aspect is something like what if the structure of the id changes. Well we write a different validation code, which allows only the new structure or maybe both structures and make a new version of the API with v2/api and v2/docs root and documentation URIs.
So I fully support your point of view and I think the other developer you mentioned does not even understand OOP and encapsulation, not to mention webservices and REST APIs.

REST collections of collections, promoting and demoting

We have a resource called tasks. With the following endpoints, we can list all tasks, and create tasks:
GET: /tasks
POST: /tasks
The problem is that tasks can contain sub-tasks, and we wish to embed the functionality to both support promoting sub-tasks to their own tasks and demoting tasks to sub-tasks of another task.
The naïve approach should be to delete the sub-task and create it again as a task and vice-versa, but we find this a tad too naive.
The second option we have come up with is to support endpoints such as the following, where {id} is the ID of the task, and {sid} is the ID of the sub-task:
POST: /tasks/{id}/add/{sid}
POST: /tasks/{id}/upgrade/{sid}
The first endpoint should add a task to another task, thereby deleting the first task and adding a copy as a sub-task to the second task. The second endpoint should upgrade a sub-task to a task from another task, thereby deleting the sub-task and adding a copy as a task.
So our question is if this would be considered good practice, or if there are some other options which we have not considered?
It's important to highlight that REST doesn't care about the URI spelling at all. However, once the central piece of the REST architectural style is the resource, it makes sense that the URIs uses nouns instead of verbs.
The REST architectural style is protocol independent, but it's commonly implemented on the top of the HTTP protocol. In this approach, the HTTP method is meant to express the operation that will be performed over the resource identified by a given URI.
Your question doesn't state what your domain looks like. But let's consider you have something like:
+-------------------+
| Task |
+-------------------+
|- id: Long |
|- title: String |
|- parent: Task |
|- children: Task[] |
+-------------------+
Creating a task could be expressed with a POST request:
POST /tasks
Host: example.org
Content-Type: application/json
{
"title": "Prepare dinner"
}
HTTP/1.1 201 Created
Location: /tasks/1
Creating a subtask could expressed with a POST request indicating the parentId in the payload:
POST /tasks
Host: example.org
Content-Type: application/json
{
"parentId": 1
"title": "Order a pizza"
}
HTTP/1.1 201 Created
Location: /tasks/2
Promoting a subtask to a task could be achieved by setting the parentId to null using a PATCH request:
PATCH /tasks/2
Host: example.org
Content-Type: application/json-patch+json
[
{
"op": "replace", "path": "/parentId", "value": null
}
]
HTTP/1.1 204 No Content
Updating a task to become a subtask could be achieved by setting the parentId using a PATCH request:
PATCH /tasks/2
Host: example.org
Content-Type: application/json-patch+json
[
{
"op": "replace", "path": "/parentId", "value": 1
}
]
HTTP/1.1 204 No Content
The above examples use JSON Patch (application/json-patch+json) as payload for the PATCH. Alternatively, you could consider JSON Merge Patch (application/merge-patch+json). I won't go through the differences of such formats once it will make this answer overly long. But you can click the links above and check them by yourself.
For handling errors, refer to the error handling section of the RFC 5789, the document that defines the PATCH method.
I also appreciate that some APIs avoid using PATCH for a number of reasons that are out of the scope of this answer. If that's the case, you could consider PUT instead. In this approach, the state of the resource will be replaced with the state defined in the representation sent in the request payload.
Alternatively you could have an endpoint such as /tasks/{id}/parent, supporting PUT. In this approach, the client just have to send a representation of the parent (such as an id) instead of a full representation of the task.
Pick the approach that suits you best.
REST is an abbrevation for the transfer of a resource' current state in a representation format supported by the client. As REST is a generalization of the World Wide Web, the same concepts you use for the Web also apply to applications following the REST architecture model. So the basic question resolves around: How would you design your system to work on Web pages and apply the same steps to your design.
As Cassio already mentioned that the spelling of URIs is not of importance to clients, as a URI remains a URI and you can't deduce from a URI whether the system is "RESTful" or not. Actually, there is no such thing as "RESTful" or "RESTless" URIs as a URI, as stated above, remains a URI. It is probably better to think of a URI as a key used for caching responses in a local or intermediary cache. Fielding made support of caching even a constraint and not just an option.
As REST is not a protocol but just an architectural style, you are basically not obligated to implement it stringent, though you will certainly miss out on the promised benefits, such as the decoupling of clients from APIs, the freedom to evolve the server side without breaking clients and making clients in general more robust against changes. Fielding even stated that applications that violate the constraints he put on REST shouldn't be termed REST at all, to avoid confusions.
I don't agree with user991710 in one of his comments that REST can't be used to represent processes, I agree however that REST shouldn't attempt to create new verbs either. As mentioned before, REST is about transfering a resources current state in a supported representation format. If a task can be represented as a stream of data then it can be presented to a client as well. The self descriptiveness of messages, i.e. by using a media type that defines the rules on how to process the data payload, guarantees that a client will be able to make sense of the data. I.e. your browser is able to render images, play videos, show text and similar stuff as it knows how to interpret the data stream accordingly. Support for such fields can be added via special addons or plugins, that may be loaded dynamically during runtime without even having to restart the application.
If I had to design tasks for Web pages, I'd initially return a pagable view of existing tasks, probably rendered in a table, with a link to a page that is able to create new tasks or a link in each row to update or delete an existing task. The create-new and update pages may use the same HTML form to enter or update a tasks information. If a task should be assigned as sub-task to an other task, you may be able to either select a parent task from a given set of tasks, i.e. in a drop-down text field, or enter the URI of the parent in a dedicated field. On submitting the task, HTTP method POST would be used that will perform the operation based on the servers own semantic, so wheter a new resource is created or one or multiple ones are updated is up to the server. The quintesence here is, that everything a client may be able to do, is taught by the server. The form to add new or update existing tasks just informs the client which fields are supported (or expected) by the server. There is actually no external, out-of-band knowledge needed by a client in order to perform a request. A server has still the option to reject incomplete payloads or payloads that violate certain constraints and a client will know by receiving an appropriate error message.
As clients shouldn't parse or interpret URIs, they will use certain text describing what the URIs do. In a browser a picture of a dustbin may be used as symbol for deletion, while a pencil may be used as symbol for updating an existing entry (or the like). As humans we quickly realize what these links are intended for whithout having to read the characters of the actual URI.
The last two paragraphs just summed up how the interaction model on a common Web page may look like. The same concepts should be used in a REST architecture as well. The content you exchange may vary more, ideally with standardized representation formats, compared to the big brother, the Web, though still the concepts of links are used to reference from one resource to other resources and server teaches clients what it needs apply here. Compared to HTML, however, you can utilize more HTTP methods than just POST and GET. A deletion of a resource's representation would probably make more sense with a DELETE method than with a POST method. Also, for updates either PUT or PATCH may make more sense, depending on the situation. In contrast of using sensible pictures for hinting users on what this link might be good for, link-relation names should be used that hint clients about the purpose of the link. Such link-relation names should be standardized, or at least express common sense such as expressed though special ontologies, or use absolute URIs as extension mechanism.
You may add dedicated links to show a collection of all tasks based on certain filters, i.e. all tasks or only parent tasks and what not, so a client can iterate through the task it is interested in. On selecting a task you may add links to all sub-tasks a client can invoke to learn what these subtasks are, if interested. Here the URIs of the tasks may remain unchanged, which supports caching by default. Note that I didn't mention anything in regards to how you should store the data in your backend as this is just some implementation details a client is usually not interested in. This is just a perfect case where a domain model does not necessarily have to be similar to a resources state representation.
In regards to which HTTP operation to perform a task promotion or demotion is basically some design choice that also may depend on the representation format the payload is exchanged for. As HTTP only supports POST and GET, such a change could be requested via POST, other media types might support other HTTP methods, such as PUT, which, according to its specification (last paragraph page 27), is allowed to have side-effects, or PATCH, which needs to be applied atomically - either fully or not at all. PATCH actually is similar to patching software, where a set of instructions should be applied on some target code. William Durand summarized this concept in a quite cited blog-post. However, he later on updated his blog post to mention that via application/merge-patch+json a more natural and intuitive way of "updating" resources could be used. In regards to form support, there exist a couple of drafts such as hal-forms, halo-json (halform), Ion or hydra that offer such definition but lack currently wider library support or a final standard. So a bit of work needs yet to put into an accepted standard.
To wrap this post up, you should design your API like you'd design your system to work for Web pages, apply the same concepts you use for interaction on typical Web pages, such as links and forms, and used them in your responses. Which HTTP operation you perform the actual promotion or demotion with, may be dependent on the actual media type and what HTTP operations it supports. POST should work in all cases, PUT is probably more intuitive to typical updates done in Web forms while patching would require your client to actually calculate the steps needed to transform the current resource' representation to the desired one (if you use application/json-patch+json in particular). application/merge-patch+json may be applicable as well, which would simplify the patching notably, as the current data contained in the form could just be sent to the server and default rules would decide whether a field got removed, added or updated.
you can divide your route with :
POST : /tasks => for create or add tasks
PUT/PATCH : /tasks => for upgrading your tasks
or even be more specific about it you can pass :id to params. I think the best approach is whenever you need to change delete update or get a specific object you must use :id in your params
PUT/PATCH/GET : /tasks/:id

Correct URI for REST calls to create & delete relationship between two entities

I need to create and delete relationships between two different entities through REST calls.
Let's say user A (the current user) is going to follow or un-follow user B. The existence of a follow relationship is denoted by the presense or absence of the Follow relationship entity (Follow(B, A) means that A follows B).
Should the calls be:
POST /api/follow/{user-b-id} // to follow
and
DELETE /api/follow/{user-b-id} // to un-follow
where the identity of user A is deduced from the token sent along to authenticate the call.
Or should they be based on the action being carried out:
POST /api/follow/{user-b-id} // to follow
and
POST /api/unfollow/{user-b-id} // to un-follow
I have doubts about which methods (POST, PUT, DELETE etc.) to use and whether the URIs should reference the action (verb?) being carried out. Since I am re-designing an API, I want to get as close to "correct" (yes, I do realize that's a little subjective) REST API design as makes sense for my project.
Correct URI for REST calls to create & delete relationship between two entities
REST doesn't care what spelling you use for your URI; /182b2559-5772-40fd-af84-297e3a4b4bcb is a perfectly find URI as far as REST is concerned. The constraints on spelling don't come from REST, but instead whatever the local coding standard is.
A common standard is to consider a collection resource that includes items; such that adding an item resource to a collection is modeled by sending a message to the collection resource, and removing the item resource is modeled by sending a message to the item resource. The Atom Publishing Protocol, for instance, works this way - a POST to a collection resource adds a new entry, a DELETE to the item resource removes the entry.
Following this approach, the usual guideline would be that the collection resource is named for the collection, with the item resources subordinate to it.
// Follow
POST /api/relationships
// Unfollow
DELETE /api/relationships/{id}
id here might be user-b-id or it might be something else; one of the core ideas in REST is that the server is the authority for its URI space; the server may embed information into the URI, at it's own discretion and for its own exclusive use. Consumers are expected to treat the identifiers as opaque units.
I have doubts about which methods (POST, PUT, DELETE etc.) to use and whether the URIs should reference the action (verb?) being carried out.
It's sometimes helpful to keep in mind that the world wide web has been explosively successful even though the primary media type in use (HTML) supports only GET and POST natively.
Technically, you can use POST for everything. The HTTP uniform interface gives you carte blanche.
PUT, DELETE, PATCH can all be considered specializations of POST: unsafe methods with additional semantics. PUT suggests idempotent replace semantics, DELETE suggests remove, PATCH for an all or nothing update.
Referencing the action isn't wrong (REST doesn't care about spelling, remember), but it does suggest that you are thinking about the effects of the messages rather than about the resources that the messages are acting upon.
JSON Patch may be a useful example to keep in mind. The operations (add, remove, replace, and so on) are encoded into the patch document, the URI specifies which resource should be modified with those operations.
Jim Webber expressed the idea this way - HTTP is a document transfer application. Useful work is a side effect of exchanging documents. The URI identify the documents that are used to navigate your integration protocol.
So if you need consistent, human readable spellings for your URI, one way to achieve this is by articulating that protocol and the documents from which it is composed.
Would it be correct to say that PUT is for replacing the entire entity (resource) and PATCH if for modifying a sub-set of the entity's (resource's) properties?
Not quite. PUT means the message-body of the request is a replacement representation of the resource. PATCH means the message-body of the request is a patch document.
There's nothing in the semantics that prevents you from using PUT to change a single element in a large document, or PATCH to completely replace a representation.
But a client might prefer PATCH to PUT because the patch document is much smaller than the replacement representation. Or it might prefer PUT to PATCH because the message transport is unreliable, and the idempotent semantics of PUT make retry easier.
The right decision also depends on the way other resources are mapped in the project. Same style is better, however if there's no preference, the following could have the advantage of being easier to implement and remember
POST /api/follow/{user-b-id} // to follow
and
POST /api/unfollow/{user-b-id} // to un-follow
I would say, use the delete verb if your are passing in the id of the relationship/link/follow from a to b. This way, it is fairly explicit your route is doing. It is accepting an id of some object and deleting it.
However, in your example, you are passing in the id of the other user, then you have to do some logic to find the relationship/link/follow object between the two and delete it. In my mind, this is more of a post than a delete because of the additional work you have to do. Regardless, it seems fairly subjective as to which one is "right",

What is the proper HTTP method for modifying a subordinate of the named resource?

I am creating a web client which has the purpose of modifying a set of database tables by adding records to them and removing records from them. It must do so atomically, so both deletion and insertion must be done with a single HTTP request. Clearly, this is a write operation of some sort, but I struggle to identify which method is appropriate.
POST seemed right at first, except that RFC 2616 specifies that a POST request must describe "a new subordinate" of the named resource. That isn't quite what I'm doing here.
PUT can be used to make changes to existing things, so that seemed about right, except that RFC 2616 also specifies that "the URI in a PUT request identifies the entity enclosed with the request [...] and the server MUST NOT attempt to apply the request to some other resource," which rules that method out because my URI does not directly specify the database tables.
PATCH seemed closer - now I am not cheating by only partly overwriting a resource - but RFC 5789 makes it clear that this method, like PUT, must actually modify the resource specified by the URI, not some subordinate resource.
So what method should I be using?
Or, more broadly for the benefit of other users:
For a request to X, you use
POST to create a new subordinate of X,
PUT to create a new X,
PATCH to modify X.
But what method should you use if you want to modify a subordinate of X?
To start.. not everything has to be REST. If REST is your hammer, everything may look like a nail.
If you really want to conform to REST ideals, PATCH is kind of out of the question. You're only really supposed to transfer state.
So the common 'solution' to this problem is to work outside the resources that you already have, but invent a new resource that represents the 'transaction' you wish to perform. This transaction can contain information about the operations you're doing in sequence, potentially atomically.
This allows you to PUT (or maybe POST) the transaction, and if needed, also GET the current state of the transaction to find out if it was successful.
In most designs this is not really appropriate though, and you should just fall back on POST and define a simple rpc-style action you perform on the parent.
First, allow me to correct your understanding of these methods.
POST is all about creating a brand new resource. You send some data to the server, and expect a response back saying where this new resource is created. The expectation would be that if you POST to /things/ the new resource will be stored at /things/theNewThing/. With POST you leave it to the server to decide the name of the resource that was created. Sending multiple identical POST requests results in multiple resources, each their own 'thing' with their own URI (unless the server has some additional logic to detect the duplicates).
PUT is mostly about creating a resource. The first major difference between PUT and POST is that PUT leaves the client in control of the URI. Generally, you don't really want this, but that's getting of the point. The other thing that PUT does, is not modify, if you read the specification carefully, it states that you replace what ever resource is at a URI with a brand new version. This has the appearance of making a modification, but is actually just a brand new resource at the same URI.
PATCH is for, as the name suggest, PATCHing a resource. You send a data to the server describing how to modify a particular resource. Consider a huge resource, PATCH allows you to send just the tiny bit of data that you wish to change, whilst PUT would require you send the entire new version.
Next, consider the resources. You have a set of tables each with many rows, that equates to a set of collections with many resources. Now, your problem is that you want to be able to atomically add resources and remove them at the same time. So you can't just POST then DELETE, as that's clearly not atomic. PATCHing the table how ever can be...
{ "add": [
{ /* a resource */ },
{ /* a resource */ } ],
"remove" : [ "id one", "id two" ] }
In that one body, we have sent the data to the server to both create two resources and delete two resources in the server. Now, there is a draw back to this, and that is that it's hard to let clients know what is going on. There's no 'proper' way of the client of the two new resources, 204 created is sort of there, but is meant have a header for the URI of the one new resource... but we added two. Sadly, this a problem you are going to face no matter what, HTTP simple isn't designed to handle multiple resources at once.
Transaction Resources
So this is a common solution people propose, and I think it stinks. The basic idea is that you first POST/PUT a blob of data on the server the encodes the transaction you wish to make. You then use another method to 'activate' this transaction.
Well hang on... that's two requests... it sends the same data that you would via PATCH and then you have fudge HTTP even more in order to somehow 'activate' this transaction. And what's more, we have this 'transaction' resource now floating around! What do we even do with that?
I know this question has been asked already some time ago, but I thought I should provide some commentary to this myself. This is actually not a real "answer" but a response to thecoshman's answer. Unfortunately, I am unable to comment on his answer which would be the right thing to do, but I don't have enough "reputation" which is a strange (and unnecessary) concept, IMHO.
So, now on to my comment for #thecoshman:
You seem to question the concept of "transactional resources" but in your answer it looks to me that you might have misunderstood the concept of them. In your answer, you describe that you first do a POST with the resource and the associated transaction and then POST another resource to "activate" this transaction. But I believe the concept of transactional resources are somehow different.
Let me give you a simple example:
In a system you have a "customer" resource and his address with customer as the primary (or named) resource and the address being the subordinate address. For this example, let us assume we have a customer with a customerId of 1234. The URI to reach this customer would be /api/customer/1234. So, how would you now just update the customer's address without having to update the entire customer resource? You could define a "transaction resource" called "updateCustomerAddress". With that you would then POST the updated customer address data (JSON or even XML) to the following URI: POST /api/customer/1234/updateCustomerAddress. The service would then create this new transactional resource to be applied to the customer with customerId=1234. Once the transaction resource has been created, the call would return with 201, although the actual change may not have been applied to the customer resource. So a subsequent GET /api/customer/1234 may return the old address, or already the new and updated address. This supports well an asynchronous model for updating subordinate resources, or even named resources.
And what would we do with the created transactional resource? It would be completely opaque to the client and discarded as soon as the transaction has been completed. So the call may actually not return a URI of the transactional resource since it may have disappeared already by the time a client would try to access it.
As you can see, transactional resources should not require two HTTP calls to a service and can be done in just one.
RFC 2616 is obsolete. Please read RFC 723* instead, in particular https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.3.

Why do we need anything more than HTTP GET, PUT, POST?

What is the practical benefit of using HTTP GET, PUT, DELETE, POST, HEAD? Why not focus on their behavioral benefits (safety and idempotency), forgetting their names, and use GET, PUT or POST depending on which behavior we want?
Why shouldn't we only use GET, PUT and POST (and drop HEAD, DELETE)?
The [REST][1] approach uses POST, GET, PUT and DELETE to implement the CRUD rules for a web resource. It's a simple and tidy way to expose objects to requests on the web. It's web services without the overheads.
Just to clarify the semantic differences. Each operation is rather different. The point is to have nice HTTP methods that have clear, distinct meanings.
POST creates new objects. The URI has no key; it accepts a message body that defines the object. SQL Insert. [Edit While there's no technical reason for POST to have no key, the REST folks suggest strongly that for POST to have distinct meaning as CREATE, it should not have a key.]
GET retrieves existing objects. The URI may have a key, depends on whether you are doing singleton GET or list GET. SQL Select
PUT updates an existing object. The URI has a key; It accepts a message body that updates an object. SQL Update.
DELETE deletes an existing object. The URI has a key. SQL Delete.
Can you update a record with POST instead of PUT? Not without introducing some ambiguity. Verbs should have unambiguous effects. Further, POST URI's have no key, where PUT must have a key.
When I POST, I expect a 201 CREATED. If I don't get that, something's wrong. Similarly, when I PUT, I expect a 200 OK. If I don't get that, something's wrong.
I suppose you could insist on some ambiguity where POST does either POST or PUT. The URI has to be different; also the associated message could be different. Generally, the REST folks take their cue from SQL where INSERT and UPDATE are different verbs.
You could make the case that UPDATE should insert if the record doesn't exist or update if the record does exist. However, it's simpler if UPDATE means UPDATE and failure to update means something's wrong. A secret fall-back to INSERT makes the operation ambiguous.
If you're not building a RESTful interface, then it's typical to only use GET and POST for retrieve and create/update. It's common to have URI differences or message content differences to distinguish between POST and PUT when a person is clicking submit on a form. It, however, isn't very clean because your code has to determine if you're in the POST=create case or POST=update case.
POST has no guarantees of safety or idempotency. That's one reason for PUT and DELETE—both PUT and DELETE are idempotent (i.e., 1+N identical requests have the same end result as just 1 request).
PUT is used for setting the state of a resource at a given URI. When you send a POST request to a resource at a particular URI, that resource should not be replaced by the content. At most, it should be appended to. This is why POST isn't idempotent—in the case of appending POSTS, every request will add to the resource (e.g., post a new message to a discussion forum each time).
DELETE is used for making sure that a resource at a given URI is removed from the server. POST shouldn't normally be used for deleting except for the case of submitting a request to delete. Again, the URI of the resource you would POST to in that case shouldn't be the URI for the resource you want to delete. Any resource for which you POST to is a resource that accepts the POSTed data to append to itself, add to a collection, or to process in some other way.
HEAD is used if all you care about is the headers of a GET request and you don't want to waste bandwidth on the actual content. This is nice to have.
Why do we need more than POST? It allows data to flow both ways, so why would GET be needed? The answer is basically the same as for your question. By standardizing the basic expectations of the various methods other processes can better know what to do.
For example, intervening caching proxies can have a better chance of doing the correct thing.
Think about HEAD for instance. If the proxy server knows what HEAD means then it can process the result from a previous GET request to provide the proper answer to a HEAD request. And it can know that POST, PUT and DELETE should not be cached.
No one posted the kind of answer I was looking for so I will try to summarize the points myself.
"RESTful Web Services" chapter 8 section "Overloading POST" reads: "If you want to do without PUT and DELETE altogether, it’s entirely RESTful to expose safe operations on resources through GET, and all other operations through overloaded POST. Doing this violates my Resource-Oriented Architecture, but it conforms to the less restrictive rules of REST."
In short, replacing PUT/DELETE in favor of POST makes the API harder to read and PUT/DELETE calls are no longer idempotent.
In a word:
idempotency
In a few more words:
GET = safe + idempotent
PUT = idempotent
DELETE = idempotent
POST = neither safe or idempotent
'Idempotent' just means you can do it over and over again and it will always do exactly the same thing.
You can reissue a PUT (update) or DELETE request as many times as you want and it will have the same effect every time, however the desired effect will modify a resource so it is not considered 'safe'.
A POST request should create a new resource with every request, meaning the effect will be different every time. Therefore POST is not considered safe or idempotent.
Methods like GET and HEAD are just read operations and are therefore considered 'safe' aswell as idempotent.
This is actually a pretty important concept because it provides a standard/consistent way to interpret HTTP transactions; this is particularly useful in a security context.
Not all hosters don't support PUT, DELETE.
I asked this question, in an ideal world we'd have all the verbs but....:
RESTful web services and HTTP verbs
HEAD is really useful for determining what a given server's clock is set to (accurate to within the 1 second or the network round-trip time, whichever is greater). It's also great for getting Futurama quotes from Slashdot:
~$ curl -I slashdot.org
HTTP/1.1 200 OK
Date: Wed, 29 Oct 2008 05:35:13 GMT
Server: Apache/1.3.41 (Unix) mod_perl/1.31-rc4
SLASH_LOG_DATA: shtml
X-Powered-By: Slash 2.005001227
X-Fry: That's a chick show. I prefer programs of the genre: World's Blankiest Blank.
Cache-Control: private
Pragma: private
Connection: close
Content-Type: text/html; charset=iso-8859-1
For cURL, -I is the option for performing a HEAD request. To get the current date and time of a given server, just do
curl -I $server | grep ^Date
To limit ambiguity which will allow for better/easier reuse of our simple REST apis.
You could use only GET and POST but then you are losing out on some of the precision and clarity that PUT and DELETE bring. POST is a wildcard operation that could mean anything.
PUT and DELETE's behaviour is very well defined.
If you think of a resource management API then GET, PUT and DELETE probably cover 80%-90% of the required functionality. If you limit yourself to GET and POST then 40%-60% of your api is accessed using the poorly specified POST.
Web applications using GET and POST allow users to create, view, modify and delete their data, but do so at a layer above the HTTP commands originally created for these purposes. One of the ideas behind REST is a return to the original intent of the design of the Web, whereby there are specific HTTP operations for each CRUD verb.
Also, the HEAD command can be used to improve the user experience for (potentially large) file downloads. You call HEAD to find out how large the response is going to be and then call GET to actually retrieve the content.
See the following link for an illustrative example. It also suggests one way to use the OPTIONS http method, which hasn't yet been discussed here.
There are http extensions like WebDAV that require additional functionally.
http://en.wikipedia.org/wiki/WebDAV
The web server war from the earlier days probably caused it.
In HTTP 1.0 written in 1996, there were only GET, HEAD, and POST. But as you can see in Appendix D, vendors started to add their own things. So, to keep HTTP compatible, they were forced to make HTTP 1.1 in 1999.
However, HTTP/1.0 does not sufficiently take into consideration
the effects of hierarchical proxies, caching, the need for
persistent connections, or virtual hosts. In addition, the proliferation
of incompletely-implemented applications calling themselves
"HTTP/1.0" has necessitated a protocol version change in order for
two communicating applications to determine each other's true capabilities.
This specification defines the protocol referred to as "HTTP/1.1". This protocol includes more stringent requirements than HTTP/1.0 in order
to ensure reliable implementation of its features.
GET, PUT, DELETE and POST are holdovers from an era when sophomores thought that a web page could be reduced to a few hoighty-toity principles.
Nowadays, most web pages are composite entities, which contain some or all of these primitive operations. For instance, a page could have forms for viewing or updating customer information, which perhaps spans a number of tables.
I usually use $_REQUEST[] in php, not really caring how the information arrived. I would choose to use GET or PUT methods based on efficiency, not the underlying (multiple) paradigms.