Rails REST 101 meets Rails 2.0 24
UPDATE:
REST with Rails
When: Saturday, October 4, 2008, 8:30am – 5:00pm
Where: FiveRuns Offices: 209 West 9th Street, Suite 100, Austin, Texas 78701
Cost: $295.00And now, on with the original article…
But You Said You Were Done
Last time, we concluded our REST 101 series.
Or so we thought.
We developed those articles when 1.2 was a mature, stable release, and when it had also become clear that 2.0 would not significantly change what had already been achieved in 1.2.
However, Rails 2.0 did fine-tune the way we develop RESTful applications in Rails, prompting us to add one more article and bring the series up to date.
REST Refresher
Let’s review what we covered in the first five articles:
- When deciding what controllers you need, think in terms of resources.
- Don’t think twice about what actions your controllers should have. Use the Golden Seven for each resource: index, new, edit, create, show, update, delete.
- A resource maps to Rails controller, not necessarily to an underlying model.
- Deliver your resources in a way that’s appropriate to the user’s experience. Some users want HTML, some want RSS, some want audio, some have big screens, some have tiny cell phone screens, some want to use your application like a web service and expect XML to be returned.
- The client application will indicate their preference with the “Accept” header in the http request. Use
respond_toin your controller to automatically map the Accept header to your response.
Once you’ve identified a resource that you want to implement, you just need to implement it RESTfully in Rails.
The Hard Way
I can’t believe I’m saying that anything in Rails is actually hard, but if there is a “hard” way to write RESTful code, this would be it (“by hand” is more precise, I suppose). Here’s the recipe:
1. If your resource needs a supporting model, use script/generate model <resource-name> (or ruby script\generate model on Windows). You can now specify any columns you already know your model needs right on the command line, which will give you a nice head start in your migration file.
Don’t forget to rake db:migrate before you start running your tests (you thought I was going to say “running your app”, didn’t you?)
script/generate model Airport city:string identifier:string
2. Generate a nice empty controller with script/generate controller <resource-name> and fill it with the standard seven actions.
script/generate controller Airports
Using textmate? You can steal our Textmate snippet to quickly write all the boilerplate code for you.
3. Create views only for the actions that need them, typically these are:
index.html.erbnew.html.erbedit.html.erbupdate.html.erbshow.html.erb
In Rails 2.0, the middle part of the template filename maps to the HTTP mime type (more or less), so you might also have files named index.iphone.erb or show.xml.builder.
Also, be sure to learn the cool new form_for syntax in Rails 2.0 that automatically generates the right target url based on whether you give it a new object (which will target the create action) or one that’s already been saved to the database (which will target the update action).
In fact for a nice overview of all that’s new in Rails 2.0, we recommend the PeepCode Rails 2.0 PDF by Ryan Daigle (disclaimer: PeepCode supports this blog.) Ryan’s blog is also an excellent way to keep up on all the new stuff in Rails.
4. Add a map.resources line to your routing file. There are lots of options here, but the simplest looks like:
map.resources :airports
This will generate a package of handy named routes, map incoming action/verb pairs to the right controller action, and automatically ensure that actions like create, update and delete only respond to POST verbs only.
But you knew all this already – it’s been around since Rails 1.2.
5. Always, always, always try to use named routes whenever you use link_to and any other helper method that expects a hash of url options. The syntax of named paths has changed somewhat in 2.0 to make it easier to construct links for the most typical scenarios. Check the Rails API docs and use the new rake routes task as a cheat sheet whenever you need it.
Help Rails Help You
Ok, now for what’s new in Rails 2.0 that can make this process much easier.
Rails 2.0 has two built-in generators to make your RESTful life easier.
1. Generating A Resource Without Views
If you have a model underpinning your resource, you can get 80% of the way done by using the totally awesome resource generator (again, available since Rails 1.2, but somehow few people know about it). It’s syntax is identical to the model generator, but it will also create a RESTful controller with the Golden Seven actions and add a map.resources line for you.
script/generate resource Airport city:string identifier:string
So what was the other 20%? The views are not generated for you.
2. Generating Everything With The Scaffold Generator
You can inch up to 95% of the way for the simplest situations by using the new scaffold generator.
Ok, time out.
We’ve always said that the scaffold generator was bad. Very bad.
So now we’re recommending it?
Not if you’re using 1.2.x or earlier. In that case, do not use the scaffold generator. If you’re using 1.2, you can use the scaffold_resource generator instead.
But in Rails 2.0, the scaffold generator is no longer evil, it is downright righteous. It will create the model, controller, routes, and view scaffolding that demonstrates how to use the new form_for syntax. Very cool stuff. Again, it uses the model generator syntax, so use the singular form of your resource and specify any columns you already know up front:
script/generate scaffold Airport city:string identifier:string
You’ll end up rewriting the views to truly fit your application, but that’s the whole idea. It’s scaffolding, not the real thing, silly.
If you’ve used the resource generator and now want the scaffolded views as well, you’re in luck: Brian Hogan has released a gem to do just that for you.
(Oh, and I know we had you at “easier.”)
Ok, NOW we’re done
We hope this wraps up our REST series. At least for now.
Questions? Comments? Applause? Complaints? Bring it on in the comments.
Simulating XML-formatted requests with a check box 11

I was working on the search form shown above in the usual RESTful manner. This form posts to a create action of my SearchesController, and the code basically looks like this:
def create
@search_results = find_matching_rows # code to search the db
respond_to do |format|
format.html # default behavior, show results in html page
format.xml { render :xml => @search_results.to_xml }
end
end
My routes file looks like this:
map.resources :searches map.resources :customers
If you've been doing any REST lately, the above code should look familiar.
The part I want to talk about today, though, is the checkbox you see at the bottom of the form.
If the user fills in some search criteria and leaves the box unchecked, they should get a normal search results view. But if they check the box, I want to return the results as XML. Why would I do this? Well, in my case, it's just so I have an easier way to check my respond_to logic (yes, yes, I already have functional tests for it, but ignore that for the moment) since it's nice to be able to see the XML come back in the browser (in Firefox, anyway... Safari doesn't seem to do this for me, I have to view source afterwards.)
Rails (1.2 and higher) support the notion of a "format" parameter, which can be automatically recognized if you're using map.resources or something like map.connect ':controller/:action/:id.:format'. You can go directly to an address like localhost:3000/customers/1.xml and Rails will set params[:format] to xml. This, in turn, is what activates the format.xml code in the respond_to block above.
However, in my case, I have a a form that I'm using to search the database. So I added this code to my form to display the checkbox:
<p><%= check_box_tag 'format', 'xml' %>XML</p>
check_box_tag is useful when you have a checkbox that can't be mapped to any attribute of your ActiveRecord model. The first argument will become the key in the params hash in your controller; and the second will become the value (there are more parameters and options you can specify, I always have to look them up every time).
The trick here is, by specifically using "format" and "xml" as the values to for the checkbox tag, we will simulate the exact values the params hash needs to make the respond_to block to work. The user checks the box, clicks Submit, and presto - XML in their browser (well, not in Safari unless you view source, but Firefox seems to know what to do).
Cool, no?
REST 101: Part 5 - Respond! 28

Photo credit: http://www.flickr.com/photos/pantagrapher/
Last time, we learned how Rails conventions enables your HTML to access your resources. But we want our software to support more than just HTML clients. Our flight schedule software needs to be accessible by web browsers, cell phones, and even third-party libraries.
As far as REST concepts are concerned, we've covered the basics in parts 1 through 4. If this was a dot-to-dot picture, we've already placed our dots. Now we can connect them and see what we've been making! This is actually one of my favorite parts about REST in Rails, because it's another example of the beautiful Ruby language underneath.
Short But Oh So Sweet
To connect our dots, we have to make our Rails controllers provide different responses depending on who's on the other end of the line. Let's take an easy example: getting a list of airports. If you used the scaffold_resource generator in Rails 1.2, you got code that looked something like this:
class AirportsController < ApplicationController
def index
@airports = Airport.find :all
respond_to do |format|
format.html # do nothing, allow Rails to render index.rhtml
format.js # do nothing, allow Rails to render index.rjs
format.xml { render :xml => @airports.to_xml }
end
end
end
The first line is easy: find all the airports. The rest of it is some weird-looking code. But that's all there is, and it's able to render the list of airports in HTML, XML, and even with some ajax when needed! So once you understand the respond_to stuff, you'll be all set.
In HTTP, client applications provide meta-information about their request in the HTTP "header". The header is just a bunch of optional key-value pairs that the client can send along. There are some predefined key names that can be used. One of the standard keys is the "Accept-Type". The client can pass along an "Accept-Type" value to indicate what kind of format the client can "accept," or understand. If it's omitted, the server assumes that the client can understand HTML. But any valid MIME type can be specified. If the client sends "Accept-Type: text/xml", then the server is supposed to respond with an XML document fragment instead of HTML markup.
So, it's this Accept-Type header that enables all of the magic inside the respond_to block. Let's imagine implementing this the lame way. Pretend that Rails could pass the value of the Accept-Type value to your action method, so you could render the correct response:
class AirportsController < ApplicationController
# Pretend that Rails will call our index action,
# and will pass in the value of the Accept-Type header
def index(client_format)
@airports = Airport.find :all
if client_format == "text/html"
# TO DO: render the default template
elsif client_format == "application/javascript"
# TO DO: return some javascript
elsif client_format == "application/xml" || client_format == "text/xml"
# TO DO: return some XML back the client
# ... more elsif statements here for each MIME type you want to support
end
end
end
Clean Up Time
You have to squint past the ugliness, but the code is pretty simple: based on the requested format, we return the correct representation of our list of airports. I imagine the core team might have started with code that was something like this (or at least in their head even if they didn't type it), and they quickly refactored by added a helper method called respond_to. Let's look at the respond_to snippet again:
respond_to do |format|
format.html # do nothing, allow Rails to render index.rhtml
format.js # do nothing, allow Rails to render index.rjs
format.xml { render :xml => @airports.to_xml }
end
First, while we might not know much about the weird respond_to method, we do know one thing - it takes a Ruby block. (If you don't know about Ruby blocks, well, go do some Googling first and then come back.) Inside the block, you get passed a rather odd-behaving variable I've called format. And then it looks like we're calling three methods on the format object.
Here's the idea: Rails can't magically know which types of clients you want to support, but it can already do 80% of the work for you. You just need to somehow indicate which kinds of clients you want to accept, and for each client, you need to render a representation of your resource that can be understood by that particular client. So instead of Rails telling you which format was requested, it expects you to tell it which formats you are able to "respond to" (get it?). And for each format, you (optionally) provide a block of your own, that is able to provide the representation for that format.
In the example above, we're telling Rails that for HTML and Javascript clients, Rails can do its default behavior - find the right template and render it, but if a client wants XML, then we supply a block with the actual implementation.
Remember, a long time ago, in a galaxy far, far away, we talked about the difference between a resource and its many possible representations? How HTML is really just one representation of a resource? ("Your application is not a web page", etc.?) Now you can even see that in our code: html is just one of the possible ways we render our resources. Awesome, huh?
Parting Advice
Naturally, we can't cover everything there is to know about REST. That's why we called it "101". But we have talked about how to design your application in a "restful" way and how it's different from traditional object-oriented design. We've talked about the concept of resources, and how they are your paradigm for your application.
Wondering what to do next? Try it! Just create a Rails app from scratch, try the scaffold_resource generator, study the code, and then try to customize the views. Try to customize the controllers. It's easier than you think.
Here are some resources I recommend (note, PeepCode supports this blog):
- The PeepCode episode on REST
- DHH's keynote from RailsConf 2006 and blog entry
- Keep up with what's new in Rails with Ryan Daigle
Got others? Link 'em up in the comments.
REST 101: Part 4 - Routing

Photo credit: http://flickr.com/photos/drdul/
UPDATE April 18, 2007: I fixed the URL convention for the "new" action to
/airports/newinstead of/airports/1;newwhich was incorrect. It's only theeditaction that uses the semicolon in Rails 1.2.
Last time we learned that a REST design starts by identifying a few key resources. Today we need to talk about how Rails will route all of the REST-compliant requests, and how it expects you to handle those requests.
I want also take a step back for a moment, and mention that REST is not a Rails-only thing. REST was developed long before Rails, and is simply an approach that can be applied to many kinds of software applications. For example, now that I know about REST, I'll probably never write another WinForms app the same way again.
Resource == Controller
You already know about models and controllers. But how do you coordinate them to implement your newly-found RESTful design? First, let's get a few things out of the way:
- A resource is not always a one-to-one mapping to a Rails model or database table. Sometimes a resource is "virtual" and exists in your domain vocabulary and application logic, but is not backed by a database table.
- However, a resource is always mapped to a Rails controller.
- For you abstract-interface lovers out there (like me), you can consider your controller class to be the "concrete implementation" of your REST interface.
- Your controller will implement your resource regardless of which kind of client is talking to it (html browser, xml client, feed aggregator, etc.) As such, it will need to be able to respond accordingly, and send its responses and return values back to the client in the format that the client expects (html, xml, etc.) Back in part 3, I said we wanted different kinds of clients (web, cell phone, rich client, etc.) to be able to access the same resources. A single controller is responsible for rendering its resource, regardless of which client is making the request.
Seven
Most resources want to be accessible individually (an airport) an as a collection (the list of all airports). Your controller will have these seven actions (methods):
These four:
- show : this handles a GET request for the representation of one resource instance.
- create : this handles a POST request for creating a new resource instance.
- update : this handles a PUT request for updating an existing resource.
- destroy : this handles a DELETE request on a resource instance.
plus these three:
- index : this handles a GET request for a representation of the collection.
- new : this handles a GET request for a blank form useful for creating a new resource. Usually makes sense only for HTML clients.
- edit : this handles a GET request for a form that is pre-filled with current values of an existing resource. Again, usually only for HTML clients.
The names of these methods are important, because the Rails routing infrastructure will be expecting them.
Of course, you can choose to implement fewer if you want. If your business rules say that a certain resource should only be rendered as read-only, then you might only need to implement the index and show methods, for example.
You may already be wondering how in the world you're going to develop a Rails application if those are the only actions you're allowed to have in your controllers. Well, first of all, don't worry. If you really, really think you have a situation that requires a few extra actions, then go right ahead and add them to your controller. Just remember that having any extra actions can be a warning sign that you haven't identified all of your resources yet.
The Traffic Cop
We need to connect some dots now. How do we map the URLs and HTTP verbs into method calls on our controller?
Normally, the action to be called in your controller is obvious just by looking at the url. I hope you remember how Rails normally translates incoming HTTP requests into calling methods in your controller code. If you don't remember, here's a five-second refresher course: your routes.rb file specifies how to translate URLs into controller classes and methods:
map.connect '/airports/:action/:id', :controller => 'airports'
This example maps a url like www.mydomain.comm/airports/open/45 to a controller class named AirportsController and a method named open. While the open method is running, params[:id] will yield 45.
But to implement REST with the Rails framework, things would need to be done differently. First of all, we will want the same url to sometimes map to different actions, depending on which HTTP verb has come along for the ride. In other words, this URL:
/airports/1
should map to our show action (for airport #1) if the HTTP verb was GET, but it should map to our destroy action if the HTTP verb was DELETE.
Prior to Rails 1.2, there wasn't a way to specify all that logic in the map.connect statement. Fortunately, 1.2 introduced a small but extremely important enhancement to the routing vocabulary. It's so cool, in fact, that unless you are aware of REST, you might have absolutely no idea how great this little enhancement really is to the Rails framework:
map.resources 'airports'
This code is short but it says a lot. It tells Rails all of these things:
- you have resources called airports (note the plural form, that's important)
- you want Rails to follow RESTful conventions and map incoming requests accordingly
- routing will not be based on URL pattern alone, but URL pattern paired with an HTTP verb
- it should route all requests to this resource through a controller named AirportsController (note, plural again)
- all URLs for this resource will follow a very specific convention (I'll describe those below)
- you want a set of pre-defined named routes for each action for this resource
The URL/verb pairs Rails will now automatically map for you look like this:
/airports/+POST= create/airports/1+GET= show/airports/1+PUT= update/airports/1+DELETE= destroy/airports/+GET= index/airports/new+GET= new/airports/1;edit+GET= editNOTE: That strange-looking semicolons are correct for Rails 1.2.3, but they will be changed to forward-slashes in Rails 2.0
Now all you have to do is implement the seven methods in your controller, and Rails handles the rest!
Don't Order Yet
But wait, there's more. There's a really neat generator that comes with Rails 1.2 and later called scaffold_resource, that will give a complete RESTful skeleton for your resource: it will add the routing code, a simple but functional controller implementing all seven methods, a migration for the underlying table, and RHTML templates for all of them! It's a great way to get started.
In fact, the best thing you can do to learn about REST is to start a fresh rails app and generate a resource. Create a database called myapp_development and myapp_test (for example), and then do this:
c:\dev> rails myapp
c:\dev> cd myapp
c:\dev\myapp> ruby script/generate scaffold_resource airport name:string designator:string
c:\dev\myapp> rake db:migrate
Start up ruby script/server and go to localhost:3000/airports. You'll be able to create new airports, edit them, and delete them! How does it work?
Just open up airport_controller.rb - it's all right there. The Ruby code will be amazingly short. Study the code. It's very important that you understand the controller code before we move on.
Then, look at each of the .rhtml templates that were generated for you, and look for the use of named routes. Get a feel for how an incoming request gets routed to a controller action and which .rhtml will get rendered back to the client.
Now, there's probably one construct in the controller code that you haven't seen before: the strange-looking respond_to block. That's an important pillar of of our entire RESTful implementation, and we'll go into more details about it next time.
REST 101 translated to French 0
Brian and I want to thank David Larlet for offering to translate our REST 101 articles into French.
If anyone else would like to offer other translations, we would be grateful. Anytime you translate any of our posts, please drop us a note so that we can announce it here and provide a link to your translations.
Again, thanks David.
Rest 101: Part 3 - RESTful Design 25

Image credit: dyobmit
Last time, we talked about the differences between a web page and a resource. Now we need to understand how resource-based design will pay big dividends.
Repositories 'R' Us
From now on, think about your application as nothing more than a resource repository. What's a repository? Subversion is a good example of a source code repository. MySQL is a relational data repository. The NHL standings in the Chicago Tribune is a read-only repository of some hockey statistics. Can you think of some other examples?
At this point, I just need to pick a repository example we can use for the remainder of this series.
The Worst Example In The World
You work for SoftiesTransAir, and you get to build their software infrastructure from scratch.
- You need a rich-client, front-end tool to enter flight information. A flight is just the definition of an airplane going from one city to another at an assigned time).
- You want a web front end for airport employees to use. You want passengers to check their flight status from their cell phone.
- And your boss wants you to expose a nice XML-based API that third-party contractors can use to update those big arrivals/departures boards inside the airport.
Sounds like a fun project, right? Remember way back in part 1, we described traditional object-oriented design, and how one good way to get started is to look at a description of your problem domain and identify the nouns (which will be your objects) and the verbs (which will become methods). Just think of all the fancy design patterns you can use! You can't wait to draw your big UML diagram on the whiteboard and go to town with some interaction diagrams! Oooh, you can already imagine the FlightSchedule.CancelFlight() and Flight.Delay() methods.
Sorry Charlie. Since you decided to go with REST, most of your design is already done for you! In fact, the only thing left to do is to just identify your resources.
Let me say that again, just in case you didn't hear me over the squeak of your dry-erase markers, because it's kind of important.
Just identify your resources.
In our example, I can quickly identify some key nouns: airplanes, airports, and flights. I'll probably discover more along the way, but that's a good start for now.
How will client applications access each of these resources? That's what URLs were invented for. (By the way, you do know what the L in URL stands for, right?) The locator for each resource follows a simple pattern. For example:
/airportsis for the list of airports/airplanesis for the list of airplanes/flightsis for the list of flights
and:
/airports/ordis for Chicago O'Hare/airplanes/ZJ3543is for the airplane identified by the serial number ZJ3543/flights/451is for Flight #451
Four Methods
Ok, once you identify your resources, REST defines the four methods (or verbs in HTTP parlance) that each of your resources can implement:
- GET. Give me a read-only view of one instance of a resource from the repository.
- POST. I have new instance of a resource that I want to add to the repository.
- PUT. I want to update a resource that already exists in the repository.
- DELETE. I want to remove an instance of a resource from the repository.
Sound familiar? In Subversion, GET is like "checkout" or "update" command. POST is like the "add" command. PUT is like a "commit", and DELETE is like the "delete" command. In the MySQL example, GET is like doing a SELECT; POST is like INSERT; PUT is like UPDATE; and DELETE is, well, DELETE.
Wow. We know our resources and we know our methods. We can stop designing and start implementing.
Calling Those Methods with HTTP
Web applications use HTTP to let the client and server to talk to each other. Now we can tie up a loose end from Part 1. What really happens when you type a URL into your browser? The browser formats an HTTP message to call the GET method on the resource identified by the URL you gave it.
You can also call the POST method from your browser - but only if there's a <FORM> element on your web page. (Ok, not strictly true thanks to Ajax, but let's not go there right now). Forms can send data to a particular URL. When you submit a form, the browser calls the POST method, passing the URL and also some data representing the resource it wants to insert or update.
You can't call PUT or DELETE in your browser using HTML natives. Which is - as I'm told I like to say - unfortunate. Although every HTTP web server in the world is prepared to accept a PUT or DELETE method call, there's no standard way to make those calls with HTML. You have to invent your own way to signal to the server that you're trying to make a PUT or DELETE call.
Bottom line: You can map your nice REST API to nice HTTP verbs, but there are no HTML tags that will make the PUT or DELETE calls. The client and server have to agree ahead of time on some kind of convention they will use to fake the PUT and DELETE methods.
Almost There
Now that our design is done, next time we we will implement it in Rails.
REST 101: Part 2 - A Million APIs
Last time, I convinced you that the world wide web is a bunch of resources, not web pages. This time we will take another step closer to what REST is all about.
Object-Oriented Analysis and Design
If you've been doing object-oriented programming for some time, you probably learned to work like this:
- Write a description of your problem domain - what your program is supposed to do.
- The nouns are your classes
- The verbs are methods on those classes
- Have your nouns call methods on other nouns to accomplish a task
Sounds reasonable. That's how I did programming for a long time. This style of noun-verb programming is often called "RPC" style. I don't know what it has to do with "remote"-ness, but just know that "RPC-style" is the "classic" way of building object-oriented software. It's actually a great way to develop software. But that's not how the web was designed to work. Why not?
Imagine it's 1992 (or just sometime before the web as you know it today). And suppose three different companies developed three different software applications: one to buy books, one to buy airline tickets, and one that can provide aerial photographs from any arbitrary distance above the earth. They each followed the classic object-oriented modeling techniques outlined above to develop their apps. And thinking that third-party software might someday want to interface with their software, they each implemented their own API as well.
Now suppose it became your job to write a tool that would front-end all three applications.
Ugh. You'd have to learn three different APIs. And I bet you would have UI controls that would correspond directly to the methods you can call in each API. But it sounds logical, right? I mean, how else could you do it? Besides, it's only three different APIs, and you know of some good books that give you some design patterns you could use to try to reduce the complexity (and look cool to your co-workers).
How about a million APIs?
Let's think about the browser again. When you install it on your computer, it has no foreknowledge of what websites you will want to visit. Yet it can communicate with any website you want. Not only that, you can take actions on those sites: you can buy music, book airline tickets, and view satellite images of your house.
Is it magic? Think for a moment how impossible things would be if each website had their own API. To buy a book on Amazon, the browser would have to know to call the Amazon.Buy() method. And it would need to call the UnitedAirlines.CheckFlights() method when I clicked a button that said "Check Flights" on it. You just can't build a tool that would have to talk to a million different APIs.
That's why the web wasn't designed from an RPC perspective. It was designed from a REST perspective.
Resource-centric Design
According to Wikipedia, REST stands for Representational State Transfer. Well... whatever. All it really means is that instead of having nouns with an arbitrary set of verbs attached to each one, every noun (from now on referred to as a resource) will have the same finite set of verbs. In other words, every resource will expose the same API. The essential methods in this API enable any client tool to:
- Obtain a read-only view of a resource
- Create a new resource
- Update the attributes of a resource
- Delete a resource
Wait a minute! Which one of these methods means "buy this book"? Which one means "search for flights from Chicago to New York next Tuesday"? Which one lets me zoom in from "city" level to "street" level on a map? And which one lets a user login to the site?
We'll find out the answer next time. But I think you might know the answer already, if you really can stop thinking about the "buy the book" web page and start thinking about what resource you might be creating. See you next time.
Questions? Suggestions? Leave a comment and tell me.
REST 101: Part 1 - Understanding Resources 24

We're starting a new series today.
For some reason, learning about REST was a bigger struggle for me than it ever needed to be. I'm not exactly sure what that was. Maybe it's because I spent so much of my life writing client applications, not web applications. Maybe it was because (read quickly now) I was getting up to speed on the whole HTTP programming thing at the same time I was learning Ruby at the same time I was learning Rails and it was right after that I went to the first RailsConf and everyone got excited about REST and I smiled like I understood so I wouldn't look like an idiot but really I had no idea what was going on... Whew.
If you're trying to make sense of what REST on Rails is all about, then this series is for you.
People who are experts in HTTP, HTML, and REST might nitpick with my simplified terminology so I can focus on the topic at hand. If that's you, I don't want to hear about it, because this series isn't for you anyway :-)
Square One
Let's begin at the beginning. How does a web browser work? Before trying to build websites with Rails, I used to think it was something like this:
- I type in a url into the address bar, or click on a link
- The browser makes an "http request" (whatever that means) and gets HTML code in response
- The browser renders the new HTML onto the page
And that was pretty much it. And I never really thought about how forms worked, either. I just figured they were a variant of the above.
In reality, the HTTP protocol includes exact instructions on how a browser should send its request to the server. HTTP is totally different from HTML, which happens to be the markup language chosen to represent the page content. It turns out that HTTP enables the browser to retrieve all kinds of information from the server, beyond simply getting an HTML page or submitting form data. In fact, HTTP actually allows for eight different kinds of requests to be made to the server. However, we are most familiar with these two kinds of requests:
- A "GET" request: get the contents of some resource on the web; the resource is uniquely identifed by a URL;
- A "POST" request: send a package of data to a URL to create a new resource.
Square Two
See how I've slipped in the word "resource" when you weren't expecting it? Well, this is where my first, critical turning-point in thinking came in trying to understand REST: thinking of the web as a collection of resources, not "web pages". What do I mean by that?
Yesterday, I went on amazon.com and looked at some products I could buy. I also read some articles on Wikipedia. I read some news headlines on CNN. Then I checked the latest NHL standings to see just exactly how far Chicago is out of the playoffs.
If you want to understand REST, you have to stop thinking of these things as web pages. Let's take a Wikipedia article as an example. It's not just a web page. It's a resource - in my case, a short biography of Archimedes. I happened to use a web browser to access that resource, so the web browser requested an HTML representation of that resource, because rendering HTML is only way web browsers can display resources.
I know this is weird at first. Isn't the Archimedes article a web page? No. I asked for the HTML representation for a resource held by Wikipedia, a resource that can be identified by the URI "//en.wikipedia.org/wiki/Archimedes". Wikipedia could have chosen to represent that resource in any number of ways - with a PDF, or perhaps as a .jpg picture. Maybe they offer all of those. But Firefox used a GET request that specified that the resource should be provided by the server as HTML, so that's what I got.
Another example: my plane reservation is a resource held by United Airlines. They let me get to that resource in many ways: as an HTML page, but they can also send my reservation information as a text message to my cell phone. Or they could send it to me in plain text in an email. Or I could call them up on this old device and they would tell it to me verbally. Same resource, multiple representations.
So I hope it's obvious now: my airline reservation is not just a web page. It's a real resource that (fortunately for me) can be rendered whenever I choose with HTML, and I can use my browser to request that representation and render it onto my screen.
Square Three
Ok, once you can accept that the web is actually a huge collection of resources that can be rendered in multiple ways, and that an HTML rendering is just one of those, then there's one more concept I want you to grasp before we stop today. Resources aren't just single things like biographical articles, or an airline reservation, or a sports statistic. Some resources are collections of other resources. A list of holidays can be a resource. A list of friends can be a resource. A series of blog posts can be a resource.
Now that you understand what resources are, tune in next time when we talk about how HTTP enables the creation, reading, updating, and destruction of resources. (Rats, I think I just gave it away.)
Questions? Suggestions? Flames? Leave a comment and tell me.



