This is a super cheap and quick design of a Java-like "pet store" application as a RESTful, resource-oriented web service. There is no implementation: what I describe should be implementable in any web framework and with any underlying architecture. You can do it with servlets, Restlet, Rails (with minor changes), etc. The only things I define are the HTTP resources, their names (URLs), the links between them, and their behavior under HTTP's uniform interface.
My goal is to give you a feel for RESTful design using an example most Java programmers are familiar with. I follow the nine-step "generic ROA procedure" laid out in chapters 5 and 6 of RESTful Web Services, which makes it easy to turn business requirements into RESTful resources.
Because I just want to give you the bare minimum of what it feels like to do RESTful design, I've skimmed over a lot of terminology, distinctions (like the distinction between a resource and its representations), and reasonable questions like "why would you want to follow links instead of generating URLs?". Because of this I do not recommend using this page as a guide to RESTful design. Chapters 5 and 6 of RWS are much more rigorous and complete. I just wanted to write down my thought processes as I turned the "pet store" application into a set of resources.
1. Figure out the dataset
The first step is to decide what data you're exposing. Since I'm cloning an existing application, this is pretty easy. I basically took this information from the database schema of an existing "pet shop" application; there are only a few touches of my own.
2. Split the dataset into resources
I'm going to have a resource for every "thing" in my application. Every piece of data the client might want to manipulate should be made a resource. I've split the data set above into nine kinds of resources:
To perform an operation in this application, the client will send a GET, PUT, POST, or DELETE request to the URI of one of these resources. No other operations are possible.
Note especially how I phrased the description of resource #5. I'm describing an algorithm in terms of its infinitely many result sets. In an RPC-style service this would be a method called something like "doSearch" or "findAnimals". In a RESTful web service, the only possible name for this method is "GET". What is it that the client is GETting? They're getting a list of search results. How does the server know the client wants search results and not something else? That identifying information comes from the URI (a.k.a URL) of the "search result" resource. That brings us to the next step:
3. Name the resources with URIs.
By decree, I name the above resources thusly. Many other arrangements are possible.
4. Expose a subset of the uniform interface
Since this is a RESTful web service, every possible action within the pet shop application must be conveyed with GET, POST, PUT, or DELETE, sent to a URI designating one of the nine kinds of resource. Given my mental image of how the application should work, I've come up with this table. If I ever need functionality that won't fit on this table, I'll create more resources. Italicized requests require authentication to make. "(superuser)" means only the superuser can make a certain request.
| Resource | GET | POST | PUT | DELETE |
|---|---|---|---|---|
| Home page | List the categories | - | - | - |
| Category | List the species in this category | - | - | - |
| Species | List the animals of this species | Add a new animal to stock (superuser) | - | - |
| Animal | Describe the animal | - | Modify the animal's description and/or price (superuser) | Remove the animal from stock (superuser) |
| Animal search results | Display results | - | - | - |
| User list | List all users (superuser) | Create a new user | - | - |
| User | Describe the user | Create a new order | Change the user's password | Delete the user account |
| Order | Describe the order | Add an animal to the order | Update order information and/or finalize it | Cancel the order (if not finalized) |
| Line item | Show status of this line item (has someone else bought the animal?) | - | - | Remove the animal from the order (if not finalized) |
There are five more steps in the procedure, but at this point you should be able to see approximately how the application is going to work. To buy an animal you might go from the home page to your user account and POST to create a new order. Then you'll find the animals you want to buy, and for each one send a POST to the order object. Finally, you'll send a PUT to the order object, providing credit card information and finalizing the order. At that moment, all the animals in your order will be marked sold and no one else will be able to buy them.
5 and 6
The next two steps are "Design the representation(s) accepted from the client" and "Design the representation(s) served to the client." I'm going to skip these for now because they're extremely implementation-dependent. You might serve HTML documents to clients and expect form-encoded submissions when a client tries to modify a resource. That is, you might be building a web site. Or you might serve XML documents with a custom schema and expect the client to modify those documents and send them back.
At this point you might call it a day and start implementing. But there is one more big step if you want your service to be truly RESTful.
7. Connect the resources to each other
Step seven solves two problems. The most obvious is that there's currently no way to move from one resource to another. The URL to the home page is obvious, but what's the URL to your user account, or the category list? You have to have read this document ahead of time and programmed your automated client with the specific URL. On the web, we use links instead of describing the URLs we want our readers to visit. The documents we serve are not just flat media files: they are hypermedia files that link to other parts of the web. The same rules apply to web services: we create links to guide an automated client from one resource to another.
These links might be HTML links, they might be URLs inside an XML
document, or they might be implemented some other way. It depends on
the decisions I made in the previous step, "Design the
representation(s) served to the client."
The figure to the right shows one way of adding links to my resources. Now they're connected to each other, the way programming-language objects in memory might be connected by a hash or a linked list. The client can access almost every resource by going to the home page and following links. But what about that outlier, the list of search results?
There are no links from the home page to a list of search results because there are infinitely many strings a client might search for. Instead of a static link, I need some way of providing a blank for the client to fill in. Fortunately, links are not the only kind of hypermedia. There are also forms. A web-based search engine has the same problem, and it solves the problem by sending you an HTML form to type into. Your browser uses the text you type to construct a URI according to predefined rules, and GETs that URI.
Depending on my hypermedia format, I may be able to add a form to the home page, a guide to constructing the URI /animals?q={query-string}. In HTML, the form might look like this:
<form class="search" method="GET" action="/animals"> <input type="text" name="q" value="" /> <input type="submit" value="Find animals"/> </form>
If the home page serves a form like that, it will be connected to the list of search results, and a client will be able to get from the homepage to anywhere in the application, without having to guess any URLs. I can totally change the URLs at will, and clients will still work.
And, depending on my hypermedia format, I may also be able to add forms that help the client modify the application. So I could add a "buy me" form to every "animal" resource. Filling this form out would result in a POST request to one of the client's open orders, which adds this animal to the order. In HTML, the form might look like this:
<form class="buy" method="POST" action="/users/leonardr/104a"> <input type="hidden" name="animal" value="/animals/RABBIT-950r" /> <input type="submit" value="Buy me!"/> </form>
That is, it might look basically the same as it would on a web site. In another representation format, the form might look different.
Forms can also describe PUT requests. A form served along with an order might show the client how to finalize the order. For the superuser, a form served along with the description of an animal might show how to modify that description. Again, the representation format determines what the form looks like (and whether it's even possible: for instance, today's HTML standard doesn't support PUT forms).
The diagram to the left shows the forms I might add to my resources if
I wanted to give my clients clues about how to make GET, PUT, and POST
requests. The previous diagram showed the links I added to make GET
requests easier. If you compare the two diagrams to the table I set
out earlier, you'll see that I've provided a link or a form for every
GET, PUT, and POST operation in the table. Assuming I can put all
those links and forms into place, a client doesn't need that table at
all! All that information is served to the client as needed.
(You don't usually need forms for DELETE operations, because there's no data to send. The client is just trying to delete something.)
8 and 9
This is where you start homing in on an implementation. Step 8 is "Consider the typical course of events" and Step 9 is "Consider error conditions." These steps are where you consider things like:
I'm skipping over these steps because they are the same problems you'd have to consider if you were implementing the pet shop any other way. The back-end solutions are usually the same as if the pet shop were a web application, but the solutions are conveyed differently to the client. It usually involves the server sending an error code and an explanatory document instead of carrying out the client's request.
Clear as mud, right?
|
This document is part of Crummy, the webspace of Leonard Richardson (contact information). It was last modified on Tuesday, June 12 2007, 23:53:49 Nowhere Standard Time and last built on Friday, November 14 2025, 02:00:18 Nowhere Standard Time.
| Document tree: Site Search: |