See here from some syntactical changes that occurred after this post was published
Following the tail of David Heinemeier Hansson’s much talked about RailsConf keynote speech comes the addition of the ActiveResource library to edge Rails. What’s all the hype about? Well, I’ll let you read David’s post for the lowdown, then I’ll try to do some justice to the concept….. Done reading? If you were too lazy let me give you the one line summary: CRUD is great because it’s consistent, simple, expressive and foundational. Every application should be built solely on CRUD operations – and Rails is going to help you construct such applications.. Great, let’s carry on.
If you haven’t noticed, it appears that the next version of Rails will whole heartedly embrace the RESTful model of application development. Not only was it the topic of David’s keynote speech, but we’ve seen a lot of updates into edge rails that support the various aspects of RESTful calls (for instance we’ve seen REST support in the various link helpers and the ability to populate a
Hash directly from XML). REST is a great companion to the RAILs style of simple, expressive application development.
for those that need a quick primer on REST, see the bottom part of this post
ActiveResource provides a large piece of the REST puzzle by basically implementing the client side of a RESTful system – the parts of a decoupled system that consume RESTful services. At its essence, ActiveResource provides a way to utilize model objects as REST-based client proxies to remote services. Ok, sounds impressive, but what does this mean?
Let’s look at an example of a typical
find call on a Person model object:
Person.find(1).name #=> "Ryan"
Doesn’t appear to be anything out of the ordinary going on here – except that under the covers it’s not a database
SELECT that’s occuring. Instead, if the Person model is an Active Resource, this
find call is actually sending an HTTP
GET request across the wire to a RESTful service:
GET http://api.myremote.com/people/1 <=
See how an XML response comes back from the
GET request? That XML is automatically transformed for us behind the scenes into a Person object. (Hmmm, now that Hash.create_from_xml addition we saw come across in edge rails a few days ago makes sense.. ). There’s a lot of power in that – transparently making a remote call (based on REST principles) simply by using the same methods you’re used to using with Active Record.
What about creating or deleting? Same thing:
Person.new(:name => "Ryan").save
POST http://api.myremote.com/people =>
<= Location: http://api.myremote.com/people/1 Ryan
With the create, a POST HTTP request is made and an XML document is submitted as the request in the format we saw come across before – the XML structure of the Person object with its values. The return value is the URL that represents where that resource now lives (from which the id of the new person can be parsed). Note: this create functionality of ActiveResource is not yet committed to edge rails, it’s been deduced from various other resources and presentations
Deletes just return a 200 status code when successful (note there’s not yet a
Person.destroy(id) class method like in ActiveRecord – you have to get the item first).
DELETE http://api.myremote.com/people/1 <= Status: 200
To be clear, ActiveResource is not meant to replace ActiveRecord in your controllers since that would involve an unecessary trip across the wire. However, when building APIs and de-coupled services, Active Resource makes perfect, painlessly simple sense in the consumption of such services. To implement the Active Resource client proxy, all you have to do is the extend
ActiveResource:Struct and point to the remote URL:
1 2 3 4
Person = ActiveResource::Struct.new do |person| person.uri = "http://api.myremote.com/people" person.credentials :name => "me", :password => "password" end
From this simple setup ActiveResource will now perform the following on each individual operation:
|Model request||Http REST operation||request body||Request URI||Response|
So we know how ActiveResource abstracts the calling of REST services from the client side, but how do we implement those RESTful services? I suspect you’re going to see the server side components flowing into edge rails for the 1.2 release, but there are already a few plugins that provide that functionality.
What is REST?
REST is the request and manipulation of web-accessible resources through the use of standard HTTP request methods (
DELETE). REST is based on the notion that the individual HTTP methods represent the type of action to take (the verb) and the URI is the location of the resource to act upon (the noun). Using this paradigm, the same URL can be used to perform different actions. For instance, if I wanted to get the person with id 1, I might make this call:
And if I wanted to delete that person, I would call the same URL with a different request type:
There you go, the noun is the URL representing a single resource, and the action to perform is the type of request. No longer do we need different URLs for every system action. One url, many actions. Powerful and concise.
Saying it in a slightly different way, REST is the invocation of an atomic, CRUD-based operation on a web accessible resources by the appropriate HTTP method instead of the URL of the request.
HTTP has several types, or methods, of making a request. We’re all familiar with
GET, used to fetch a resource or URL, and
POST which is most often used to submit form data. However, there are also the
DELETE methods of requests (among others) that largely go unused. The whole idea behind REST is to properly synchronize the intent of the request with the method of the request.
It’s not uncommon to see the following URL to delete an item:
http://url/people/delete?id=1. Somebody requests that URL and the resource is deleted from the server. But, this represents a break between the effect of the request and the type of request. When a browser or application requests that URL (via a
GET), a deletion occurs within the system. How a deletion should be requested is with the HTTP
DELETE method. That way the method of the request (
DELETE) matches the effect of the request (something is deleted). There are similar mappings between every REST action and the basic CRUD operations:
|CRUD operation||REST method|
You will often see REST and CRUD being compared as they mirror one another – REST is how CRUD operations are invoked in an HTTP-networked environment.References:
- David Heinemeier Hansson; RailsConf Keynote
- Maurice Codik; Instant REST on Rails: Active Resource
- Casper Fabricius; RailsConf: Create, Read, Update, Delete: Normalize