Rails Misapprehensions: CRUD is not REST!

While doing some research on Rails and REST, I took stock on two things.

  • It is relatively hard to find a clean, basic and printed explanation of how REST works with Rails. I found thousands of screencasts, and this single great guide.
  • People do confuse CRUD with REST.

Especially the latter kept annoying me. While coaching a team I found out that clearly separating CRUD and REST helps people understanding what RESTful really means: Nothing more than HTTP restrictions.

I felt like sharing this insights with you.

Tell me, what is CRUD?

Every application has exactly one purpose: Maintaining business objects. This basically means: You got models that need to be created, displayed, updated and deleted using forms, lists and other fancy web UI elements.

If your Rails app would be managing beers, you’d write a BeersController with actions like show, update, create and so on. The actions would mostly display forms and save attributes to models.

In order to access these forms in the browser you’d create routes, like

  • /beers/show/:id
  • /beers/new
  • /beers/delete/:id

and map them to the respective controller actions I already mentioned.

This is what we call a CRUD interface: An application with descriptive routes, forms and usually pretty boring code – having one destiny: To Create, to Retrieve, to Update and to Delete.

Hey, this is CRUD!

Now, what’s REST?

Couple of years ago a new standard emerged, it is called REST and has the following main principles:

  • The central concept of REST is the resource, which is a datastructure representing one or more business objects.
  • REST also encourages clean, simple, yeah, “RESTful” URLs – like /beers/1
  • They use HTTP verbs (GET/PUT/POST/DELETE) to encode what to do in the request, not in the URL.
  • Something called content negotiation: We could request the resource in HTML representation, in XML, and more.

That’s what REST recommends, it does not say a word how to do it, just that we should.

What’s the difference?

I was wondering what differentiates REST from CRUD. Strictly speaking, both concepts ask the same two questions:

  • Which resource are you interested in?
  • What you wanna do with the resource?

Are there more similarities?

  • The resource is the business model in CRUD.
  • The CRUD route itself contains the verb (like edit or show) whereas REST encodes this information in the HTTP request type.

Again, the real difference is: Our CRUD code already implements this behaviour, whereas REST only recommends a standard for URLs (which I do appreciate!).

REST on Rails

Now, what Rails’ REST code does is nothing more than providing some “RESTful” helpers.

The real logic, the CRUD code, is still up to you (unless you’re using José’s InheritedResources).

How does Rails help me with REST?

  • It ships with a routing helper resources that creates numerous named RESTful routes for you.
  • Some helpers as form_for automagically link to RESTful URLs for you depending on the model’s/resource’s internal state.

The essential thing about REST

The really cool thing about REST – beside nice, standardized URLs – is: you get a public API for free!

Folks can

  • query your models by GETting /beers/1.xml, which usually returns a nicely formatted XML representation of your model if your code provides it.
  • write to your database by POSTing to /beers where they simply add POST parameters to fill in attributes in the new resource.

And so on.

They don’t need wiring code or a special binding library, they can just use HTTP to fuck up your database. Isn’t that great?

What’s your problem now, Nick?

Ok, summing things up, our logic is still CRUD, it’s not RESTful.

When speaking about short URLs and about different request types we should refer to REST. The rest… is CRUD (haha, a word-play!). REST is just a thin layer above our CRUD implementation, telling us how to format requests and URLs.

People will never understand the exceptional – the cool thing – about REST if we keep confusing CRUD and REST.

14 thoughts on “Rails Misapprehensions: CRUD is not REST!

  1. There’s nothing about short or long URLs in REST really.

    I’ll just leave those here:

    http://en.wikipedia.org/wiki/HATEOAS ( this is what Rails misses, the main diff of ‘restful’ and REST – hypermedia awareness )

    http://www.ics.uci.edu/~taylor/documents/2002-REST-TOIT.pdf – Roy’s original thesis, everyone pretends to have read it, but you know, just in case (:

    Probably the best source on the practical side:

    As for implementation, I quite like Cloudkit ( http://getcloudkit.com/rest-api.html ). Though it includes resource metainfo in headers, not in the body.

    Implementation for Rails is a subject of RSoC, you can find it at http://github.com/caelum/restfulie. Hopefully we’ll be able to use it soon.

    Like

  2. Nick,

    A couple of clarifications.

    A resource is not necessarily the same thing as a business objects. You may have transient resources for which there are no business but which may modify a business object.

    An example. Lets say you have a Blog model and a User model and you wish to allow Users to subscribe to Blogs. In Rails, you normally end up adding a User to a Blog or a Blog to a User (that is you either POST to /blogs/12/subscribers or to /users/233/subscriptions) or you may allow both for ease of use and symmetry.

    This is an essentially CRUD operation, I’m either updating my User or my Blog.

    REST allows us to take a totally different point of view. If you were to follow the REST architectural style exhaustively you would typically define a Subscription Resource. This resource would likely not correspond to any business object but rather would represent a number of distinct operations performed against business objects. Lets say that the representation of our Subscription model is something like:

    {
    “blog”: “http://example.com/blog/23123”,
    “subscriber”: “http://example.com/user/32212312”,
    }

    This would be posted to /subscriptions and would result in updating both the blog and subscriber models appropriately.

    You’ll notice that I’ve specifically passed a URI for each of the members of the subscription. This is intentional. In REST you ALWAYS pass URIs to identify other resources. Rails fails to do this and it seriously holds back the possibilities of Rails. A URI is simply a network address. Why do I need to know that the resource is on my own network? Why does it have to be a user? Why couldn’t it be a content aggregator or some such (lets pretend that our subscribers are pushed updates)? Association via URI (and all the polymorphic, duck typing flexibility that implies) will be the next great leap in software development.

    The second thing you get wrong in your article has to do with is the URIs.

    Your statement “REST also encourages clean, simple, yeah, “RESTful” URLs – like /beers/1” is absolutely false. A simply clean URI is useful ONLY as a tool for communication with people. It has value but in and of itself is not REST.

    To be properly restful, you need to ask yourself, what would happen if I replaced all my URIs with GUIDs. That is instead of the subscriber resource above, it should be equally meaningful to use:

    {
    “blog”: “http://example.com/40DBED2E-E2DB-11DF-89B9-E9D3DFD72085”,
    “subscriber”: “http://example.com/6258C97C-E2DB-11DF-B28E-18D4DFD72085”
    }

    If you were to do this in a normal rails app, you’d likely send:

    {
    “blog”: 23123,
    “subscriber”: 32212312
    }

    Right now unless you use restfullie with rails (http://restfulie.caelum.com.br/) Rails APIs are not REST at all. The key missing ingredient is Hypertext As The Engine Of State.

    Adam

    Like

  3. I agree with you Nick.
    REST concept, changed my mind about web clients (html pages ¹ JS ).
    Now , when I write apps, I think my views as REST API clients. I drive me to some great designs, and helps me to keep coherent pretty URI rules.

    Like

  4. for me it sounds like there is a problem in the differentiation of a concept, pattern or logic (CRUD) and a standard (REST) which enables us to use the concept in the same way.
    as nick pointed out, it makes sense to be aware of it to use it in a accurate way to get all the benefits.

    Like

  5. You say REST uses “HTTP verbs (GET/PUT/POST/DELETE)”, but actually REST architecture does not say anything about HTTP specifically. HTTP is simply implementation of the REST architecture. REST exists at a higher level separate from HTTP. You could have (and there are) technologies other than HTTP that implement REST.

    Like

  6. @d: You’re right, I should have said “Resources can be manipulated using verbs usually encoded in the HTTP header but not necessarily bound to HTTP”. Do you know anything about alternative protocols suitable for REST? I’d be eager to see that in practice.

    Like

  7. I don’t think it fails. You could get a XML or JSON resource and use it on your “aggregation resource”. It’s not that difficult, and actually I did this a lot.

    Like

  8. This is actually incorrect. REST goes beyond just a URL convention. The METHODS have semantics which do make it a bit more similar to CRUD than you realize.

    GETs should be cacheable at various edge locations
    POSTS and PUTS and DELETES should not.

    When you think about what a resource is, the GET verb indicates that you are fetching it (something should be returned). The POST verb updates it. Nothing need be returned (the convention of returning a “hydrated” object is a hack since you already have the hydrated object that you posted. Just make another GET request if you need the latest state.

    Things like nested associations over Rails’ version of REST is flawed b/c it creates all kinds of cache expiry headaches which break much of the usefulness of the verbs that REST is built on.

    Like

Leave a comment