I’ve heard a lot about REST in my early days of Rails (Rails 3 was just around the corner, so it’s not THAT early) and I understood it was using the HTTP verbs GET, PUT (now PATCH), POST and DELETE and allowed Rails developers to have statelessness in their URIs, among other things.
I read up on it and understood that REST allowed for proxies and caching. I was happy with that, went along with it and created routes like this:
resource :reports, only: :show do member do get :line_item_overview get :invoices_us get :invoices_uk get :fees get :cc_payments get :sales_by_product get :donations ... end end
There’s more, but you get the point. Also see Robert Martin’s opinion on reports.
I understood the
resource keyword as a nice shortcut to get the basic CRUD actions for my model. Whenever I needed “something special”, I created a
member or a
collection route. This seemed like the Rails way to me.
I just ignored the warning given right above non-resourceful-routes in the rails routing guide:
If you find yourself adding many extra actions to a resourceful route, it's time to stop and ask yourself whether you're disguising the presence of another resource.
Yeah whatever. What’s too many anyway? I didn’t even start to think that there could be some theory behind resource orientation. But now I want to know what it would look like to have my example be resource oriented.
I surfed around a bit and found an explanation of Resource Oriented Architecture (ROA):
ROA is just four concepts:
2. Their names (URIs)
3. Their representations
4. The links between themand four properties:
4. A uniform interface
“Just”, without any explanation. It’s a bit like saying set theory is just 10 axioms:
- Schema of specification
- Power set
- Choice (to have ZFC)
Now go and proof that the Continuum hypothesis is independent of ZFC…
Turns out the source for these 4 concepts and 4 properties is this little gem. Assuming you didn’t read it before finishing this paragraph I’ll try to sum up what seems important to me here:
Resource-Oriented Architecture is also RESTful. But REST is not an architecture: it’s a set of design criteria. You can say that one architecture meets those criteria better than another, but there is no one “REST architecture.” ... In RESTful architectures, the method information goes into the HTTP method. In Resource-Oriented Architectures, the scoping information goes into the URI. The combination is powerful.
Ok. That’s all pretty railsy. Notice that query parameters are part of the URI, so it’s uncommon to see a rails app that has scoping information somewhere else. I guess scoping for the current_user without including them in the url might be the most common violation of this principle.
The "four" concepts
A resource is anything that’s important enough to be referenced as a thing in itself.
So in the routes file above I can find a couple of resources:
- the fees-report
- the report for us-invoices
- the report for uk-invoices
I didn’t use the
resource keyword in my example, though. Maybe I should? Let’s read on:
A name of a resource is their URI. In my example
my-site.org/reports/invoices_us is a name for a resource. Note that
my-site.org/reports/invoices?country="us" would be another name for the resource, as parameters are a part of the URI (I wrote that a second time, because I keep on looking that up).
A representation of that resource would be the HTML for that report. Another one might be a PDF, or even a JSON-String with the data, or even the printed report on paper. The resource can have multiple names in that case for different representations of it:
A web server can’t send an idea; it has to send a series of bytes, in a specific file format, in a specific language. This is a representation of the resource.
The main point seems to be that the resource is independent as a concept from its representation and it’s name. You never really get a resource, only their representations. I think that might be helpful somehow…
I honestly don’t really get why links are in the list as well. Can’t a JSON-API without links to other resources still be resource oriented? I’ll just ignore it for this post and I’ll also ignore the connectedness property because the article is “calling the quality of having links connectedness.”
The "four" properties
Since resources are exposed through URIs, an addressable application exposes a URI for every piece of information it might conceivably serve. This is usually an infinite number of URIs.
Seems obvious but again, having information scoped by a current user, that’s not set from the current_url means that not all pieces of information are addressable. Also In my example above there is not an infinite number of URIs. Query parameters are the reason for the infinite number and I don’t have them for my reports.
Statelessness says that the possible states of the server are also resources, and should be given their own URIs.
A state can be a search result, or the result of any other algorithm, so that seems unsurprising to me as well. I get the feeling this deserves more attention, but I have to get to the end.
The important thing about REST is not that you use the specific uniform interface that HTTP defines. REST specifies a uniform interface, but it doesn’t say which uniform interface. GET, PUT, and the rest are not a perfect interface for all time. What’s important is the uniformity: that every service use HTTP’s interface the same way. The point is not that GET is the best name for a read operation, but that GET means “read” across the Web, no matter which resource you’re using it on.
Why is that good? You have THE SAME verbs in all the internet! It’s like getting vaccinated: It helps others. The variance will only be in the resources and their names. This is less useful if you click around on a website. But it’s really nice for APIs. Theoretically you could write one library that just have to know the resource names of each consumed service, if everyone would adhere to ROA. Theoretically…
A better version
OK. So all this is not a big deal for my example. I had a resource oriented architecture before. I just didn’t set it up within the Rails conventions. Understanding what a resource is lead me to rewrite my routes to look like this:
namespace :reports do resource :line_item_overview, only: :show resource :invoices, only: :show resource :fees, only: :show resource :cc_payments, only: :show resource :sales_by_product, only: :show resource :donations, only: :show ... end
Which has the added bonus of me being nudged to move logic out of my mighty reports controller.
Even if my example didn’t change much I learned a lot. I keep on underestimating how much theory is behind rails and the web in general. There is a lot to know about software architecture. For example this presentation contrasts
- object orientation (as in ruby!)
- resource orientation (which I just described)
- service orientation (as in SOA everyone is talking about)
that just blew my mind.
I’ve spent way more time on this article then I planned, but I still managed to leave out the the main difference between REST and Remote Procedure Calls (RPC). The difference is that the “method information” goes into the HTTP-verb. But I’m still unsure if that’s REST or ROA and I’m unsure what exactly “method information” is. I think it should be the difference between GET
my-site.org/counter?reset and POST
my-site.org/counter-reset but I don’t have the time to make sure right now. I’ll just try not to write my own verbs and instead have a counter-reset resource instead of a
CounterController with a reset action for now and research a bit more later.