Rest 101: Part 3 - RESTful Design 22

Posted by jeff Tuesday, April 10, 2007 14:21:00 GMT

flight info on cell phone

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:

  • /airports is for the list of airports
  • /airplanes is for the list of airplanes
  • /flights is for the list of flights

and:

  • /airports/ord is for Chicago O'Hare
  • /airplanes/ZJ3543 is for the airplane identified by the serial number ZJ3543
  • /flights/451 is 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.

Comments

Leave a response

  1. Peter   April 10, 2007 @ 04:22 PM

    I'm loving the whole idea of resource based development but I've yet to find any articles putting these basically good ideas together in a real world situation. Can't wait for your next installment ;)

  2. David Parker   April 10, 2007 @ 04:49 PM

    Peter, here's a good source: http://www.b-simple.de/documents

    Jeff, I'm lovin' the way you are explaining REST so far-- keep up the good work!

  3. Shane Vitarana   April 10, 2007 @ 09:37 PM

    A very helpful series of articles. No one else has put it so simply and clearly. Thanks!

  4. Derek   April 11, 2007 @ 01:30 AM

    I'm loving these articles. I am your biggest fan.

  5. Dillone   April 11, 2007 @ 02:07 AM

    It's great explaining!!! I've read all 3 parts of the articles. I hope to introduce your work into China.

  6. Shawn Oster   April 11, 2007 @ 03:02 AM

    Great articles, I think they'll help people looking to get a handle on these things.

    One thing that I think is important to stress is that REST has nothing to do with Ruby on Rails. The concept of REST has been around for ages and I used to impliment REST-style services with both classic ASP and PHP even before the SOAP madness. In fact, REST was really the way things were done until everyone got SOAP crazy and now it's finally starting to shift back.

    I'm sure other readers understand this but someone really new to programming may get confused and start thinking RoR is the only way you can do REST, which would be a pity because it's always better to have an understanding of a concepts than a framework.

  7. Jeff   April 11, 2007 @ 03:32 AM

    Thanks for the encouragement, everyone! I appreciate it.

    @Shawn: Good point, and I'll try to make that clear in the next installment. I think my WinForms development could have benefitted greatly from a REST design, for example.

  8. Francisco Hernandez   April 11, 2007 @ 07:30 AM

    I was really intrigued about what you said on part 2, "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"

    I also didn't see an example how you would represent FlightSchedule.CancelFlight() and Flight.Delay() using REST

    I can't say I've designed a full on REST style app but I still have issues with representing things such as searching, using REST, oh and also something like "has this file been processed" for polling long running processes

  9. Julien Boyreau   April 11, 2007 @ 09:00 AM

    Hi Jeff,

    Thanks for this very interesting series. I would have several remarks/questions for you.

    Based on your "airports" examples :

    1) How do you encode the more specific noun "the airports I LIKE" ? => I think we CANNOT described the world reality without verbal forms;the goal should be to integrate them within REST i.e to state "I like this airport" = to POST an airport TO the "like" URL will create a LIKED airport.

    2) "Plural" should NOT be encoded within the english word as this could allow translations easily. => May be "/airport/" could translate to "the airports" = ending with "/" means "plural"

    3) What if you have an airport (Common noun) called Airport (Proper noun) ? => Proper and common nouns should be syntaticly distinguished

    If interested, I have developped these idea in this article. http://www.u-blog.net/syd1980/note/210

    Thanks for comments.

  10. Jeff   April 11, 2007 @ 01:41 PM

    @Francisco: I'll be showing how we implement concepts like CancelFlight() and Delay() and REST in the next article; but the short story is, both are just PUT operations on a given Flight instance. PUT is used to update attributes of an existing resource; so CancelFlight() and Delay() would simply pass the appropriate attribute name/value pairs that need to be updated to the PUT method. The key with thinking in REST is to think, ok, if I had to do Create/Read/Update/Delete something, what would I be doing? And it's suprising how many of our old-style methods really boil down to CRUD on some resource somewhere in your app. I hope it will be clear in the next article, but if not be sure to ask me again :-)

    @Julien: for your 1), I think you're talking about nested resources, a concept I haven't covered yet, but probably will before the series is over. Basically, associations between resources like you have (users and airports) can be represented by nesting resources, which is a way of limiting scope. Your url in your example would probably be /user/9/airports, which would list only those airports that the user "likes" or are their "favorites". As for your other questions, can you rephrase? I'm not sure I understand the question about plurals and proper nouns being distinguished in the url..?

  11. Julien Boyreau   April 11, 2007 @ 05:44 PM

    Hi jeff,

    Thanks for feedback. My main point is two fold : We NEED verbal forms for URLs written from natural language : /user/9/airports does not tell me if these airports are the ones I have SEEN, LIKED, HAD SEX AT, BEEN, BUILD, FORBID...

    We NEED common vs. proper nouns differentiation : what if a user is called John "User" ? How to tell the computer "user" here is the Concept not the Name.

    Eventually my idea is to give meaning to "/", "#", "_", "+", "?", "="... to allow people to make these distinctions at the URL level.

    Julien

  12. John Topley   April 12, 2007 @ 04:35 PM
    @Francisco: I'll be showing how we implement concepts like CancelFlight() and Delay() and REST in the next article; but the short story is, both are just PUT operations on a given Flight instance. PUT is used to update attributes of an existing resource; so CancelFlight() and Delay() would simply pass the appropriate attribute name/value pairs that need to be updated to the PUT method.

    I remember that DHH gave entities, events and relationships as examples of resources, so might we also choose to model this with FlightCancellation and FlightDelay resources? That way we could easily get a list of all cancelled or delayed flights.

  13. s0nspark   May 16, 2007 @ 01:39 AM

    Thanks so much for this ... I've been "wRESTling" with RESTfulness the past few days trying to put it in perspective and your tutorial helped me place it... I had grasped the mechanics of it but not the methodology... Understanding that REST is resource-centric (and, of course, resource == controller) did the trick!

    Thanks so much!

  14. adrian   July 01, 2007 @ 10:37 PM

    Jeff, you are right, I think all operations can be represented as REST. Sometimes its only a question of trying to see if we are missing some resources that can help us to translate more complex operations into CRUD ones.

    What I find difficult in the context of some web applications is how to render some init pages. Using rest is easy to access the resources, but I couldn't find the proper way to represent a main page or a control panel with lots of independent widgets (that uses its own resources) without apart me of rest. Do I need to use a Page Resource?...

  15. Jeff   July 02, 2007 @ 03:51 PM

    @John: Yes, those would be very good candidates for resources. And the wouldn't have to map to an underlying table. A FlightDelay controller could just provide a filter on top of flights with certain conditions applied.

    @adrian: Excellent question. A lot of us wrestle with this one. I have an OverviewController, and think of the control panel page as a resource unto itself; the index view renders a bunch of partials to help gather up the various resources into a single page. But I think everyone has their own approach to this at the moment; I don't know of any one way that's better than another.

  16. F. Lawrence   August 21, 2007 @ 12:28 PM

    Excellent presentation. I started with Part III and it is very well narrated and easy to understand. Appreciate your good work.

  17. Paul   October 07, 2007 @ 06:20 AM

    Your going places Hemingway!

  18. Scott Barr   November 12, 2007 @ 03:01 AM

    The HTTP methods, HEAD and OPTIONS, can be useful in your RESTful services as well. A response to a HEAD request returns information about a resource, but without the content body. The useful information returned in the headers, such as content-length and last-modified. The response to an OPTIONS request lets the client know what HTTP methods a location supports.

    Thanks for the well written article Jeff. I imagine you omitted these methods to help keep the examples discussed simple and focussed.

  19. Mike Schinkel   December 04, 2007 @ 09:03 PM

    Do you know this blog doesn't print correctly? In IE7 is prints 8 pages of (almost) nothing, and in FireFox it just prints three pages where the first and last are mostly blank and second page has only the beginning of the post. I've seen this happen before on Mephisto-powered sites. Is it endemic to Mephisto?

  20. Pablo   February 29, 2008 @ 04:43 PM

    I've never seen REST explained so simple and so easy to understand. kudos!

  21. kino   May 24, 2008 @ 01:14 AM

    Aristotle tells us that the discipline of practical reason is just as necessary as metaphysics.

  22. Ellroy   May 30, 2008 @ 11:24 PM

    The manifold teaches us nothing whatsoever regarding the content of, in other words, the paralogisms, but our a posteriori concepts exist in our a posteriori concepts.

Comment


(won't be published)