REST and Controller Best Practices

REST is an approach to building web applications that takes as much advantage of the underlying structure of the web as possible. This makes a lot of things more comfortable:

  • Users will find that the applications work as they’d like in their web browsers. They can bookmark pages and come back to them, and the URLs are actually meaningful.

  • Network administrators can use all their preferred techniques for managing web traffic without worrying about disrupting an application.

  • You, of course, get the greatest benefits. REST-based architecture is a very neat fit with Rails’ MVC approach, and makes it easier to keep track of which code does what where. Rails 2.x is also set up to make it extremely easy for you to use REST, supporting a number of ways for you to say, “I’d like this to behave RESTfully.”

REST doesn’t create new techniques so much as dust off old techniques and encourage developers to use them as they were designed to be used. Of course, even early in the Web’s development, developers hacked and slashed their way into a different style of programming, so there are some adjustments to make. Fortunately, Rails makes it easy to adjust and opens new horizons in doing so.

Note

REST stands for REpresentational State Transfer, which describes what happens but isn’t the most immediately meaningful explanation.

Websites and Web Applications

Web developers have historically used two HTTP methods to get information into and out of sites: GET and POST. On the surface, GET used the “data-fits-into-the-query-string” approach, whereas POST used the “we-have-a-nice-clean-URL-with-data-elsewhere” approach. There’s more to it than that, though.

Much of the Web is read-only, and for those applications GET worked very smoothly. Browser caches and proxy servers could check once in a while to see if a page had changed. For many applications, where POSTs were used to add new data and GETs were used to see that data, things weren’t much more complicated. Unfortunately, though, the reliance on GET and POST overloaded those methods and created some problems.

For GET, the most obvious problem was that URLs became very large very quickly as more and more data was exchanged. Beyond that, though, were some other creative issues:

  • Proxy servers generally treated a GET request as an opportunity to cache information and reduce the amount of traffic needed next time. This could lead to sensitive data stored on a not-necessarily-secure proxy server and could also create some strange problems around the proxy server checking whether the result had changed when another request came through with the same data.

  • Some applications used links containing GET requests to ask for changes in data—even deletions. (Think http://example.com/doIt/?action=delete.) As the quest for speed became more important, developers came up with browser extensions that pre-fetched information from links in the document… and activated these actions without the user expecting it. Oops.

The general rule with GET has become “make sure that none of your GET requests do anything dangerous.” GET requests are supposed to be idempotent, yielding the same result even when issued multiple times. No GET request changes the results of the next GET request to the same resource, for example.

Note

PUT and DELETE requests are also supposed to be idempotent—PUTting the same thing repeatedly yields the same data that was PUT, while DELETE-ing the same thing repeatedly yields the same nothingness. HEAD requests, which are basically a GET returning headers only, are also idempotent.

POST had a simpler problem that could be avoided through careful programming, and a harder problem that was largely political:

  • Pretty much nothing created with POST was bookmarkable, unless the receiving application immediately created a redirect to something reflecting the result of the POST. Entire applications were often written so that users could bookmark only the front page. For internal applications this might be tolerable, but all these POST requests also blocked search engines, which pretty much only used GET.

  • Once it became clear that using GET for heavy lifting created problems, POST wound up carrying nearly all of the data transfers from users to the server, and then pretty much all purely computer-to-computer transfers. XML-RPC, SOAP, and most discussions of “web services” really meant “HTTP POST to a given URL” when they said Web.

The old way of working with the Web mostly worked, but it clearly had some dark corners and plenty of room for improvement. As it turned out, all the pieces needed for that improvement already existed.

Toward a Cleaner Approach

Although developers had become accustomed to using just these two methods, and browsers had given them the greatest support, HTTP had more pieces to offer than just GET and POST. The two most important of these are PUT and DELETE, which combine with GET and POST to give HTTP a complete set of verbs for manipulating data.

Note

HTTP also has a HEAD method, which is kind of a GET-lite frequently used to check on the freshness of cached data, and OPTIONS and TRACE. These aren’t used explicitly in REST models.

How can you manage data with just POST, GET, PUT, and DELETE?

As it turns out, it’s a familiar question for many programmers, who often work with the cheerfully named CRUD model, which stands for Create, Read, Update, and Destroy. If you’ve worked with SQL, you’re already familiar with CREATE, SELECT, UPDATE, and DELETE. That basic set of verbs manages practically everything we do with databases, and the art of using SQL is about skillfully combining those generic verbs with specific data to accomplish the tasks you need to accomplish.

In Rails, this is typically described as show, create, update, and destroy, as you saw in the links in Figure 5-5. You’ll also see that pattern in the controller Rails creates as part of the scaffolding. Working this way requires a shift in the way developers think about controllers, and about writing web applications generally.

The example created in the previous chapter treated the controller as a container for actions, for verbs. You could, if you wanted, write an entire Rails application in a single controller, with a method for every action it offers the user, and views to match. Those methods would then work with a variety of different models, getting information into and out of the application. If that became too large a mess, you could use a number of controllers to group different methods, though there would be lots of different ways to group them.

The example built with scaffolding takes a very different approach. The publicly available verbs are standardized—each controller implements the same verbs. Instead of being a container for a wide variety of actions, the controller becomes a standardized piece connecting a data model to the Web: a noun.

This maps perfectly to the way that REST expects the Web to work. Our familiar URLs (or Uniform Resource Identifiers, URIs, as REST prefers to call them) connect the client to a resource on the server. These resources are the nouns that the HTTP verbs work on, and the controller makes sure that those standardized verbs work in predictable ways on the data models underneath.

REST offers one last bonus. “Resources” are information, not necessarily information frozen into a particular representation. If a user wants the same information in XML instead of HTML, the resource should (if you’re being nice, and Rails is nice by default) be able to provide the information as XML. By using Rails’ RESTful features, you’re not just creating a website, but a resource that other applications can interact with. This also makes it much easier to create Ajax applications on top of Rails, and to build mashups. Effectively, it’s what a rich interpretation of “Web Services” should have meant in the first place.

Warning

Thinking too hard about resources can lead to some complicated philosophical irritations. The authors have learned through painful experience that trying to sort out the proper relationship of XML namespaces to the resources that identify them is infinitely complicated, as is interpreting the meaning of a fragment identifier (#id) in any situation where the same resource can produce multiple data representations.

The answer to these irritations is simple: don’t think about them. If you find yourself going down the resource philosophy rathole, step back and focus on something more practical. These issues can create the occasional practical problem, but generally they sit quietly unless stirred up.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset