It's OK for GET Requests to Update the Database
Listen to this article
We've all been indoctrinated into associating the HTTP request methods POST, GET, PUT and DELETE with the standard database (aka CRUD) operations Create (INSERT), Read (SELECT), Update and Delete respectively. For the most part the analogue holds. When we make a GET request, our intention is to read whatever the server hands back. When we POST some data, our intention is to update something.
The general view however, seems to be that the HTTP methods relate directly to database operations. In fact many developers seem to think that they are in fact one in the same thing: POST is for INSERTing data, GET for SELECTing, etc. The popularity of which seems to have strengthened with the growing interest in REST and the wide-spread adoption of Rails 21. In fact read of the HTTP/1.1 Method Definitions specification explicitly states that so-called "Safe Methods" such as GET:
... SHOULD NOT have the significance of taking an action other than retrieval.
But what happens when we have a site that tracks where you have visited, updates the "last read date" on each record retrieved, or remembers the last search criteria you used? Each of these features requires recording information into some kind of database--be it relational or simply a log file.
What people seem to overlook is the paragraph that follows in the same document:
Naturally, it is not possible to ensure that the server does not generate side-effects ... The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.
The HTTP methods should be used to indicate the user's intention without regard to the underlying implementation. The web application is an abstraction so we need to model the interaction on that abstraction. If the user's intention is to make a change to something then go ahead and use a PUT but if they're only reading some data use a GET even if you know it involves some database writes.
It may seem somewhat esoteric but spending a bit of time thinking about what the user's intention is exactly has helped me better flesh out an application's API.
1 I don't mean to imply that Rails is the culprit here. Nothing in Rails explicitly makes these assertions. However the fact that the idiom is explicitly referred to as CRUD resources certainly doesn't help.
Comments
Excellent post (as was the last one, on response codes) - I've been doing a lot of thinking about REST, resources, and how they map onto Rails applications lately (for a couple of reasons), and I'm excited to see that the community is pondering these topics seriously, as opposed to just working with what the core team has added to the framework. I also think you're dead on in looking back at the HTTP spec for guidance, since that's an acknowledged and obvious influence on how REST was designed and articulated. Keep up the great content!
Posted by: Ben | April 15, 2008 10:40 PM
Although I agree with the spirit of the article, it is not clear form the statement, "POST is for INSERTing data, GET for SELECTing" as to what the developer intends to INSERT/SELECT. Not every INSERT/UPDATE affects domain data/business objects- i.e. the resources that GET serves or POST publishes. Other support objects, such as preferences, may be updated as a side effect of a GET while remaining within the constraints of HTTP.
Also the argument regarding, "when we have a site that tracks where you have visited, updates the "last read date" on each record retrieved, or remembers the last search criteria you used" is somewhat fragile in that:
* page tracking has nothing to do with HTTP resource in question; it is an application workflow side effect
* 'last read date' is domain concern, not of the resource; it has nothing to do with the HTTP interaction itself, but is a side effect of the same
* 'last search criteria used' would be modeled as resources created when the search is first POSTed and retrieved in subsequent GETs; hence remaining completely within specified behaviour of HTTP
It is my opinion that explicitly mixing actions on resources performed in response to a method invocation violates the generally accepted axiom of each method having one and only one job. Also, updating resource data on GET could possibly bring the idempotent nature of GET under question.
Posted by: Saager Mhatre | April 23, 2008 12:39 AM
I suspect I've not made myself clear as we're in heated agreement.
Posted by: Simon Harris
|
April 23, 2008 09:32 AM