In part 1 of this two-part post, I explained my concern that the word “resource” has become too closely associated in Rails-related usage with some combination of model, database table, and controller/model stack—none of which do justice, as definitions or even first approximations, to the concept of a REST resource as originally described by Roy Fielding. Here, I’m going to expand on this observation by exploring a few ramifications of the same topic.
Resources, controllers, and models (or lack thereof)
As I explained in the previous post, the concept of “resource” has no database implications—indeed, no implementation implications. A resource does not have to have a corresponding model. It also does not have to have a corresponding controller. Resources are far more high-level than controllers and models. Controllers and models are tools with which you provide access to representations of resources.
However, if you want to draw a line between resources and Rails, by far the better line to draw is the one that points to controllers rather than models. A controller is not a resource, but it comes closer than anything else in your application to taking on the features of your resources. Models are another big step away.
If controllers are closest to resources, how does this play out? One way is in the creation of resources for which requests are handled by a controller that has no corresponding model.
My favorite example of a likely modelless resource is the shopping cart. In Ruby for Rails, I use a shopping cart in my central example. When I started working on this application, I tried to model it directly; I imagined I would have a ShoppingCart class, a shopping_carts table, and so forth.
I quickly realized, however, that I didn’t need that. What I was calling a “shopping cart” was really a virtual construct or, in Rails terms, a view. I had Order objects and Customer objects, and the shopping cart was basically a screen showing all of a particular customer’s open orders. Calling it a “shopping cart” was just a kind of semantic sugar. There was no need to persist it separately from the persistence of the orders and the customer.
If I were writing the same application today using RESTful idioms, I would in all likelihood do:
map.resources :customers do |c| c.resource :shopping_cart end
or words to that effect. I would then have a shopping_carts controller, with a show action (probably leaving all the related CRUD stuff back in the orders controller, though there might be several ways to approach that part of it). And I would, without hesitation, describe the shopping cart as a resource—even though it has no ShoppingCart model behind it. From the perspective of the consumers of my resources, it doesn’t matter whether there’s a ShoppingCart model (and shopping_carts database table) or not. I can decide on the best application design, and use RESTful Rails techniques to support my design decisions appropriately.
A resource is not a model, and it’s also not a controller. Identifying the resource with the controller is, however, somewhat closer to the mark. The controller layer conforms most closely to the resource mapping, which makes sense since the controller is the port of call when someone connects to your application.
Another area where misunderstandings arise in the course of designing RESTful services in Rails is in the matter of how identifiers (URI) map to resources—and not just how, but how many.
Identifiers and resources: not always one-to-one
I’ve seen people tie themselves in knots trying to come up with the best way to label and/or nest resources. One of the principles that’s gotten lost in the mix is that the ratio between resources and identifiers does not have to be one-to-one. Fielding states:
[A] resource can have many identifiers. In other words, there may exist two or more different URI that have equivalent semantics when used to access a server. It is also possible to have two URI that result in the same mechanism being used upon access to the server, and yet those URI identify two different resources because they don’t mean the same thing.
Therefore, it’s possible that this:
can identify the same resource, which would probably be described as something like “The welcome and orientation information at dabsite.com”. The reason they’re the same resource is not that they generate the same HTML. Rather, they’re the same resource because they’re published as the same resource.
It’s also possible that this:
http://dabsite.com/orders/211 # 211th order in the system
http://dabsite.com/orders/042208-003 # third order placed on 4/22/08
identify different resources, even if the third order placed on 4/22/08 happens to be the 211th order in the system. That’s because resources are not database rows. In this case, the two requests might generate the same HTML, but still pertain to different resources.
You don’t have to make a point of having a non-one-to-one ratio between your resources and your identifiers. Just be aware that if such a ratio emerges, in either direction, you’re not doing anything inherently “unRESTful.”
CRUD and REST and resources
One of the nice things about the REST support in Rails is that it dovetails with CRUD-based thinking about modeling. I add in haste: REST is not CRUD, and CRUD is not REST. (That’s no secret, but I want to go on record with it.) But in Rails, there’s a nice relationship between them.
The REST support in Rails emphasizes the convention of CRUD operations. map.resources gives you a fistful of named routes that have built-in knowledge of CRUD action names. The emphasis on CRUD at this level encourages you to think of modeling for CRUD. Instead of having, say, a users controller with a borrow_book action, you can have a loans controller with a create action. In many cases, this way of thinking might also wag the dog of your domain modeling. Thinking about CRUD in the controller might, for example, lead you to conclude that you should have a Loan model.
It’s perfectly fine—indeed, in my view, it’s very productive—to think along these lines, to bring your modeling and your REST-friendly CRUD operations into harmony, as long as you understand that none of this is actually about resources as such. Rather, it’s about the Rails flavor of implementing the handlers that underpin the creation of resource representations.
Does that sound like just a lot of extra words? It isn’t. It’s a lot of words, but they’re not extra. Again, it’s important not to squeeze the entire framework into the “resource” label. Let a resource be a resource, and let the handler layers be handler layers. They’re nicely engineered—but they’re not resources.
And then there’s the word “representation,” which crept into my “extra words” sentence but which is the least extra of all of them.
Representations: the one that got away
The representation is, in my view, the one that got away: the central concept in REST that no one in the Rails world ever seems to talk about. We need to, though. It’s vitally important.
Your server does not traffic in resources. It traffics in representations of resources. Users of your application do not receive resources. They receive representations. The distinction is big; at stake is the entire meaning, and meaningfulness, of the notion of a resource.
We need the concept of “representation” because it’s the part of REST theory that relieves the pressure on the term “resource.” After all, how can a resource be a “conceptual mapping” (Fielding) and a sequence of bytes that a server sends you and a controller-model stack…? It can’t, and it’s only the first of these things. The second, the response itself, delivers a representation of a resource.
One resource can have many representations. There’s no big news here; we all know that a server can give us a text version of Jane Eyre or a movie version or an audio version. (I’ll refrain from getting philosophical about whether or not a book and a movie are “the same” in any deep sense. They’re the same enough, in this context.) The point is that we don’t need to mush everything into the term “resource.” Rather, we benefit by yanking that term up to the high level where it belongs, and applying the term “representation” to the actual response we’re getting.
Fielding has much more on representations in his dissertation, and I’m not going to try to paraphrase it here. My point is to encourage the liberal use of the term in Rails discourse about REST. The poor term “resource” has already been given too much to do. We need to delegate some of the domain description to the other terms that apply to it.
The use of the term “resource” to mean things that, I’ve argued here, it really doesn’t mean is rather deeply entrenched, and widespread, in Rails discourse. I don’t have any quick fix for this. I do have a few recommendations, though.
First, read Roy Fielding’s dissertation. You can skip to chapters 5 and 6 and get a great deal out of them.
Second, pay particular attention to the concept of the representation. I don’t think we can get much further in exploring REST and Rails unless the representation makes a comeback. “Resource” is just plain spread too thin in the way it’s used in and around Rails, and there’s no reason why it has to be, if we look at the theory as a whole.
Third, and last, don’t assume that any deviation from the out-of-the-box behaviors in your RESTful Rails applications is unRESTful. The defaults are in place because they’re high percentage. But they’re just as opinionated as the rest of Rails, and in some respects more so. That’s OK, but do understand that they’re REST-friendly tools. They’re not a definitive statement on the entirety of what REST is.
REST is not an easy topic, and it’s unlikely that anyone is going to create a way for you to create and maintain RESTful applications, over time, without you trying to get a handle on it and developing your own understanding of resources, representations, requests, and responses. I hope these posts will help you out in that endeavor.
Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures.. Doctoral dissertation, University of California, Irvine, 2000.