O'Reilly logo

RESTful Web Services by Sam Ruby, Leonard Richardson

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 12. Frameworks for RESTful Services

As the REST design philosophy becomes more popular, new frameworks are springing up to make RESTful design easy. Existing frameworks are acquiring RESTful modes and features. This, in turn, drives additional interest in REST. In this chapter, I and a few knowledgeable contributors show you how to write resource-oriented services in three popular frameworks: Ruby on Rails, Restlet (for Java), and Django (for Python).

Back in Chapter 1 I said that REST isn’t an architecture, but a way of judging architectures. The Resource-Oriented Architecture is an architecture: it imposes constraints on your thinking that make it easy for you to break a problem down into RESTful resources. But these resources still only exist on an abstract level. They aren’t real until you expose them through specific web services.

If you’re writing a service from scratch (say, as a CGI script), you can translate your resources into code however you like. But most services aren’t written from scratch: they’re written using a web framework. A REST-aware web framework imposes constraints on your programming that make it easy for you to implement RESTful resources in a specific programming language. In this chapter I’ll show you how to integrate the lessons of this book with real frameworks.

Ruby on Rails

The simplifying assumption is the main driver of the success of Ruby on Rails. Rather than give you a large number of tools for accomplishing any task you can think of, Rails gives you one way to accomplish a wide variety of common tasks. You can create a Rails application very quickly if you’re trying to expose data from a relational database, if your database tables have certain names and structure, if you care to work with a Model-View-Controller architecture, and so on. Because so many problems in the web application domain fit these assumptions, the effect is rarely onerous and often liberating.

Earlier versions of Rails exposed a textbook REST-RPC hybrid architecture, but Rails 1.2 focuses on a more RESTful design. Perhaps this was inevitable: HTTP’s uniform interface is just another simplifying assumption. I’ve already shown in Chapter 7 how Rails can be used to make sophisticated RESTful services in very little code. In this section, I take a step back and describe the RESTful architecture of Rails in more general terms.


When an HTTP request comes in, Rails analyzes the requested URI and routes the request to the appropriate controller class. As shown in Example 12-1, the file config/routes.rb tells Rails how to handle certain requests.

Example 12-1. A simple routes.rb file

# routes.rb
ActionController::Routing::Routes.draw do |map|
  map.resources :weblogs do |weblog|
    weblog.resources :entries

A config/routes.rb file can get fairly sophisticated. The one in Chapter 7 is relatively complex: I had a lot of resources, and I had to fight the simplifying assumptions a little bit to get the URI structure I wanted. Example 12-1 shows a simpler routes.rb file that buys into the simplifying assumptions.

That file declares the existence of two controller classes (WeblogsController and EntriesController), and tells Rails how to route incoming requests to those classes. WeblogsController handles requests for the URI /weblogs, and for all URIs of the form /weblogs/{id}. When present, the path variable {id} is made available as params[:id].

EntriesController handles requests for the URI /weblogs/{weblog_id}/entries, and all URIs of the form /weblogs/{weblog_id}/entries/{id}. The path variable {weblog_id} is made available as params[:weblog_id], and {id}, if present, is made available as params[:id].

Variables like {id} and {weblog_id} are typically used to associate a resource with a particular object in the system. They often correspond to database IDs, and get plugged into the ActiveRecord find method. In my del.icio.us clone I tried to give them descriptive names like {username}, and used them as identifying names rather than IDs.

Resources, Controllers, and Views

As I showed in Chapter 7, every Rails controller might expose two kinds of resources. You can have a single “list” or “factory” resource, which responds to GET and/or POST requests, and you can have a large number of “object” resources, which respond to GET, PUT, and/or DELETE. The list resource often corresponds to a database table, and the object resources to the rows in the table.

Each controller is a Ruby class, so “sending” an HTTP request to a class means calling some particular method. Rails defines five standard methods per controller, as well as exposing two special view templates through HTTP GET. For illustration’s sake, here are the seven HTTP requests made possible by my call to map.resources :weblogs back in Example 12-1:

  • GET /weblogs: A list of the weblogs. Rails calls the WeblogsController#index method.

  • GET /weblogs/new: The form for creating a new weblog. Rails renders the view in app/view/welogs/new.rhtml. This view is a hypermedia file describing what sort of HTTP request the client must make to create a new weblog.

    In other words, this is an HTML form (though it could also be a small WADL file). The form says that to create a new weblog, the client should send a POST request to /weblogs (see below). It also tells the client how to format its representation of the new weblog, so that the server can understand it.

  • POST /weblogs: Create a new weblog. Rails calls the WeblogsController#create method.

  • GET /weblogs/{id}: A weblog. Rails calls WeblogsController#show.

  • GET /weblogs/{id};edit: The form for editing a weblog’s state. Rails renders the view in app/view/welogs/edit.rhtml. This view is a hypermedia file describing what sort of HTTP request the client must make if it wants to edit a weblog’s state.

    In practice, this means the view is an HTML form, or short WADL file. The hypermedia file tells the client how to send or simulate a PUT request to /weblogs/{id}.

  • PUT /weblogs/{id}: Change a weblog’s state. Rails calls WeblogsController#update. The “state” here is the state associated with this particular resource: things like the weblog’s name and the author’s contact information. Individual entries are exposed as separate resources.

  • DELETE /weblogs/{id}: Delete a weblog. Rails calls WeblogsController#delete.

You probably won’t expose all seven access points in every controller you create. In particular, you probably won’t use the special views unless you’re running your web service as a web site. This is no problem: just don’t implement the methods or view files you don’t intend to expose.

Outgoing Representations

Rails makes it easy to send different representations of a resource based on the client’s request. Example 12-2 shows some hypothetical Ruby code that renders three different representations of a weblog. Which representation is sent depends on the URI the client accessed, or on the value it provided in the Accept header. A client will get the HTML rendition if it accesses /weblogs/1.html, but if the client accesses /weblogs/1.png instead, the service will send a graphical PNG rendition. The respond_to function takes care of interpreting the client’s capabilities and desires. All you have to do is implement the supported options, in order of precedence.

Example 12-2. Serving one of several representations

respond_to do |format|
  format.html { render :template => 'weblogs/show' }
  format.xml  { render :xml => weblog.to_xml }
  format.png  { render :text => weblog.generate_image, 
                       :content_type => "image/png" }

Two especially common representation formats are HTML and the ActiveResource XML serialization format. HTML representations are expressed using Rails views, as they would be in a human-oriented web application. To expose an ActiveRecord object as an XML document, you can just call to_xml on an object or a list of objects.

Rails plugins make it easy to expose data in other representation formats. In Chapter 7, I installed the atom-tools Ruby gem so that I could render lists of bookmarks as Atom feeds. In Example 7-8 I have a respond_to code block, containing clauses which distinguish between requests for Atom and generic XML representations.

Incoming Representations

Rails sees its job as turning an incoming representation into a bunch of key-value pairs, and making those key-value pairs available through the params hash. By default, it knows how to parse form-encoded documents of the sort sent by web browsers, and simple XML documents like the ones generated by to_xml.

If you want to get this kind of action for your own incoming representations, you can add a new Proc object to ActionController::Base.param_parsers hash. The Proc object is a block of code whose job is to process an incoming representation of a certain media type. For details, see the Rails documentation for the param_parsers hash.

Web Applications as Web Services

Rails 1.2 does an excellent job of merging the human web and the programmable web. As I showed in Chapter 3, Rails comes with a code generator called scaffold which exposes a database table as a set of resources. You can access the resources with a web browser, or with a web service client like ActiveResource.

If you use a web browser to access a scaffold service, you’re served HTML representations of the database objects, and HTML forms for manipulating them (generated by the new.rhtml and edit.rhtml I mentioned earlier). You can create, modify, and delete the resources by sending new representations in form-encoded format. PUT and DELETE requests are simulated through overloaded POST.

If you use a web service client to access a scaffold service, you’re served XML representations of the database objects. You manipulate objects by modifying the XML documents and sending then back with PUT. Non-overloaded POST and DELETE work like you’d expect.

There’s no more compelling example of the human web’s basic similarity to the programmable web. In Chapter 7 I largely ignored this aspect of Rails for space reasons, but it makes a compelling argument for using Rails if you’re designing a web site and a web service to do the same thing. Rails makes it easy to expose them both as aspects of the same underlying code.

The Rails/ROA Design Procedure

The following list is a modified version of the generic design procedure from Chapter 6. It’s what I used, unofficially, to design the service in Chapter 7. The main difference is that you divide the dataset into controllers and the controllers into resources, rather than dividing the dataset into resources. This reduces the chance that you’ll end up with resources that don’t fit Rails’s controller system.

  1. Figure out the dataset.

  2. Assign the dataset to controllers.

    For each controller:

    1. Does this controller expose a list or factory resource?

    2. Does this controller expose a set of object resources?

    3. Does this controller expose a creation form or editing form resource?

      For the list and object resources:

      • Design the representation(s) accepted from the client, if different from the Rails standard.

      • Design the representation(s) served to the client.

      • Connect this resource to existing resources.

      • Consider the typical course of events: what’s supposed to happen? The database-backed control flow from Chapter 9 should help here.

      • Consider error conditions: what might go wrong? Again, you can often use the database-backed control flow.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required