“CRUD is not REST”:http://nicksda.apotomo.de/2010/10/rails-misapprehensions-crud-is-not-rest/ is what I was trying to clarify in my last restful post. There surely is a terrible confusion in the community about that.
* *CRUD is implementation* where you simply could pull in some module into your controller and get a CRUD interface for free.
* *REST is an implementational approach* – there simply is no library that after inclusion makes your code _”restful”_. There are great gems to give you CRUD code and make it available as a REST interface. However, the real work like *deciding which and how resources are exposed, is up to you*, the software architect.
*REST is more than HTTP restrictions*. That’s what I found after studying all the great comments in the last post. Thanks for the helpful links and explanations, guys!
This *really is just the tip of the iceberg*, “as Juan stated correctly”:http://nicksda.apotomo.de/2010/10/rails-misapprehensions-crud-is-not-rest/#comment-645.
h3. HTTP restrictions?
With CRUD in mind, REST initially seemed to be nothing more than a constraint saying: _Put your verbs from the URL to the HTTP header._
Instead of having a URL like @/users/new@ I simply send a POST to the @/users/@ resource. Being _”RESTful”_, *a POST is defined to create a new resource*.
So, great, we got GET, POST, PUT and DELETE that are – more or less – *semantically mapped to CRUD operations*.
h3. RESTful urls
Browsing some Rails discussion about REST you can often *find the term _”RESTful url”_*, which usually refers to something like
Following “Adam’s explanation”:http://nicksda.apotomo.de/?p=465&preview=true#comment-646 this has nothing to do with REST – *it’s a friendly URL, nothing more!*
So the real point about URLs in REST is: They are *network addresses pointing to a unique resource.* If it is pretty, so much the better! Thanks to Rails we got friendly URLs, but keep in mind that this alone doesn’t make ’em RESTful.
Let’s look at the term _resource_ to find out how real REST urls look like.
h3. What are resources?
In CRUD context I said that *resources are _usually_ mapped to business objects*, like users, comments or any other model with a _database table_.
_Usually_ here means: *Resources could (and should!) be just anything.* They don’t need to map to distinct tables. *Transient resources – like a blog feed aggregating posts – are the crucial point about REST*. That’s where we have to act as architects deciding what to expose.
Taking the feed as example *a real resource identification* would be
A *REST id is always a complete URI* with host, path, etc.
So on the one hand *we have primary keys identifying model instances, and on the other we have REST ids*. It’s easy to confuse that!
In a _RESTful environment_ you precisely shouldn’t talk about _”user 4711″_ but about the ressource @http://example.com/users/4711@. *REST is about hiding implementation details*, why, this being the case, are we talking about primary keys?
REST usually operates via HTTP, which doesn’t mean that resource controllers need to render HTML only.
Rails 3 already does a pretty good job here. Controllers and models have *built-in renderers for different representations of resources*.
class Feeds < ApplicationController respond_to :html, :xml, :csv def index @feeds = Feed.all respond_with(@feeds) end
When requesting an XML list of available feeds *the controller will detect that, delegate to the model* and returns an XML document without having written any user code at all.
Anyway, what’s still missing here is *content negotiation*.
h3. Content negotiation
Let’s take the ruby way to illustrate that problem. I use “restfulie”:https://github.com/caelum/restfulie to write a quick REST client.
Restfulie.at("http://localhost:3000/feeds/"). accepts("application/xml"). get!
Restfulie is a wonderful gem. This code will retrieve my feeds in XML. Here’s my server output.
Started GET "/feeds/" for 127.0.0.1 at 2010-12-... Processing by FeedsController#index as XML
Obviously, this worked.
Now, *content negotiation implies that we can request a list of acceptable representations*.
What if I say _”I want your feeds in ATOM first. If you don’t speak ATOM, gimme XML!”_.
Restfulie.at("http://localhost:3000/feeds/"). accepts("application/atom"). accepts("application/xml"). get!
Restfulie takes care of the content negotiation, which is pretty awesome. Information about *which formats to send is handled in the @Accept:@ header flag*.
Started GET "/feeds/" for 127.0.0.1 at 2010-12-... Processing by FeedsController#index as APPLICATION/ATOM Completed 406 Not Acceptable
Well, I’d say *the content negotiation failed*, although we do provide XML!
What happened? Rails didn’t look at the second accepted format. This usually is not a problem, as most people don’t use content negotiation. *Restfulie provides a convenient module to enable your controller of real content negotiation*. I’ll post about that separately.
The reason for my lack of understanding here is that Rails simply doesn’t support it, yet. This isn’t a severe bug, *I just want to point out what else is in REST*.
A couple of comments “remarked another principle”:http://nicksda.apotomo.de/2010/10/rails-misapprehensions-crud-is-not-rest/#comment-644 in REST that is often swept under the table: *Hypermedia support.*
*When I hear _hypermedia_ I think of JPEG images and links*. Not sure why.
It first seemed strange to embedd workflow-related links into my resource representation. This basically means *the resource contains links to other “application parts“* where browsing to would make sense in the current application state.
Consider we were looking at a XML representation of a feed – *while it contains a lot of post snippets, it could also contain a link to actually _subscribe_*.
The feed list *_proposes_ what to do from here*. Isn’t that great?
While it is the client’s job to extract that links and decide which action to display, *the client as-it is not responsible for generating these links*. The resource provides us links to change the application state – *this is called HATEOAS*.
While I am still exploring this field of REST I just started realizing how *HATEOAS can help building forward-compatible, modular applications*.
Did I really manage to work out that REST is more than GET, POST, PUT and DELETE?
So, REST has five basic concepts, that are
* *Unique resource identification* which is sometimes mistaken as _RESTful url_
* *Standard interface* for resources like GET, POST and friends. Each request type has its own semantic and may or may not alter the resource.
* *Representations* and content negotiation to display resources in different apparels.
* *Hypermedia* to embedd further actions into the resource.
* and *stateless communication* – why not write about that separately?