(Personally, I think it would be healthier if we worked out the wrinkles in REST by writing lots of code rather than writing lots of blog entries, but blog entries are easier, and XML people have never been shy about pontificating, so here goes …)
Joe Gregorio has an excellent article on REST at XML.com, and I recommend that anyone interested in building an XML data app with REST rather than RPC (Web Services, etc.) take a look at it. However, one point in the article jumped out at me. Joe mapped CRUD to the standard HTTP verbs like this:
CRUD | HTTP |
---|---|
Create | POST |
Retrieve | GET |
Update | PUT |
Delete | DELETE |
Personally, I’ve always seen the mapping more like this:
CRUD | HTTP |
---|---|
Create | PUT |
Retrieve | GET |
Update | PUT |
Delete | DELETE |
In other words, PUT does double duty for both Create and Update. Of course, the sad point is that almost no actual REST applications work this way — most of them are read-only, so GET is the only verb that counts, and when they do allow updating information, they do not do it by sending an entire resource representation (i.e. XML file) via PUT.
What about POST?
I think there are actually two roles that POST can play in a data application:
- Partial, in-place updates (i.e. send just pieces of changed information, rather than a whole resource).
- Actions (i.e. buy a book).
For example, consider this resource representation (fancy REST talk for “file”) using POX:
<pet-record xml:base="http://www.example.org/pets/lassie.xml" xmlns:xlink="http://www.w3.org/1999/xlink"> <name>Lassie</name> <gender>f</gender> <dame xlink:href="spot.xml">Spot</dame> <sire xlink:href="jenny.xml">Jenny</sire> <offspring xlink:href="marmaduke.xml">Marmaduke</offspring> <offspring xlink:href="snoopy.xml">Snoopy</offspring> </pet-record>
Now, let’s say that Lassie has another puppy. Using REST, there are two obvious ways to update this information. The first is to download the XML file (using HTTP GET), add an extra offspring element, then upload the modified file (using HTTP PUT):
<pet-record xml:base="http://www.example.org/pets/lassie.xml" xmlns:xlink="http://www.w3.org/1999/xlink"> <name>Lassie</name> <gender>f</gender> <dame xlink:href="spot.xml">Spot</dame> <sire xlink:href="jenny.xml">Jenny</sire> <offspring xlink:href="marmaduke.xml">Marmaduke</offspring> <offspring xlink:href="snoopy.xml">Snoopy</offspring> <offspring xlink:href="clifford.xml">Clifford</offspring> </pet-record>
The second option is simply to send the REST server a message that it should add an extra offspring, by using HTTP POST to a URL like http://www.example.org/pets/updates/add-offspring
and using parameters to identify sire or dame and offspring. I don’t know that it’s possible to say that either of these approaches is better; obviously, the POST approach would make more sense for very large resources.
The other use of POST would be to execute options that do not have an obvious correspondence with resource representations/files. A good example would be posting to a URL http://www.example.org/pets/actions/buy
including parameters describing the pet you want to buy (i.e. the URL of the pet’s XML file — we’re RESTful, after all) and the price you are willing to pay.
The one use I don’t see for POST is uploading entire XML files, except as a way to work around firewalls that block PUT. Maybe we should fix the firewalls, or maybe we’ll just have to learn to live with this (ab)use of POST as a practical necessity for making REST work with the current web infrastructure.
I agree about the “write code, not blogs” comment and really should just shut up about this, but am drawn to it like a moth to a flame, with similar results, at least on my productivity. Here’s what I would hope is my last word on the subject for awhile: Find the principles of Web development by induction from the most technically successful sites, not by deduction from Fielding’s or anyone else’s axioms. That is, identify those web applications (human-only or automated services) that are secure, reliable, scalable, capable of handling all sorts redundant or aborted operations without doing anything unpleasant, etc. … then identify what the common factors are. If they do turn out to be something like: (borrowing heavily from the Wikipedia article on REST)
* Entities conceptualized as abstract resources about which applications transfer representations.
* A fundamentally stateless client/server interaction where participants are not required to take additional steps to track states
* A limited number of well-defined protocol operations that correspond fairly closely with the basic CRUD functions required for data persistence.
* A universal means of resource-identification and -resolution: in a RESTful system, every piece of information is uniquely addressable in a single namespace through the use of a URI .
* The use of hypermedia both for application information and application state-transitions.
THEN, let’s all treat these (or Fielding’s original wording) as axiomatic and figure out how to write better apps by being RESTful. If some of these aren’t found too often in the wild, then let’s not waste energy arguing about how to implement them.
This has practical implications for what David’s post analyzes: Why not just use POST as a pragmatic way of sending entire XML files to a server? Why “fix” servers by opening PUT, in the world we live in where all sorts of slimeballs are trying to sabotage websites just for kicks? If it turns out that there is solid empirical evidence that the REST prescirption about operations should be taken as axiomatic, then sure, fix the servers in the way the theory prescribes. But if the REST principles just happen to partially intersect actual best practice, it’s not clear to me why practice should change to accomodate the theory.
I’ve always thought POST made perfect sense for CREATE. “Post” as in “Post a new item”.
Take, for example, a RESTful interface to message board / forum software. URI space like the following makes sense to me:
GET / – Get links to the list of messages in the forum.
GET /id – View message “id”
POST / – Create a new message on the forum (response: 303 with URI to new resource)
PUT /id – Create a new message using the specified ID.
I think it comes down to whether the client understands how to create new pieces of URI space or whether the server needs to. If the server understands the URI space then POST makes sense, if the client understands the URI space then PUT makes sense.
There was some really excellent discussion on PUT vs. POST for new resource creation on the ATOM mailing list and Wiki back around November.
HTTP 0.9 includes the same definition of POST that Joe used (post a message to usenet or create a something somewhere). PUT and DELETE are namespace operations. PUT to create requires client control over the server’s namespace.
Robert: That’s a good point. I’m happy agreeing that sites should conform to HTTP. I guess I think of POST in *practice* as a sortof generic doStuff() operation, but I wouldn’t want to press that point. My main skepticism is about the REST as a theory for how to build more complex systems on top of HTTP.
I think the discussion here is more valuable than my original post. Will it show up in the weblog search engines, or should I summarize it in a new post?
Thanks, everyone.
For the APIs I’ve designed so far I’ve end up with POST doing the work of both create and update.
E.g. POST to /pets to create a new pet. The POST containing the required metadata, the server responds with a 302 with the URL of the newly created pet resource. This allows the server to keep control over the ids. I’ve justified this as considering “/pets” as a resource that I’m modifying.
Updates for an individual pet would be POSTed to e.g. /pets/lassie. The POST contains an XML document which can be the entire, updated pet description or just the revised elements. This is trivial when your API is mapping back to a relational system and you end up just updating individual columns; updates to document oriented XML might be a bit trickier.
I don’t understand your “/pets/actions/buy” example. Here I’m creating another resource on the server: a transaction, or wishlist, or adding to a cart.
FWIW, both POST and PUT can do creation; PUT for when the client knows the URI of the thing it’s trying to create, and POST for when it doesn’t.
“should I summarize it in a new post?”
Has it influenced your thinking? If so, yes.
Pingback: Dion Hinchcliffe's Blog - Musings and Ruminations on Building Great Systems
Pingback: Dion Hinchcliffe's Blog - Musings and Ruminations on Building Great Systems