[ I apologize for all the acronyms in the first paragraph of the post. I will explain what one of them means over the course of this entry, but if you’re here for, say, video game thoughts instead of technical geekery, then you would be correct in interpreting that as a sign that you should hit the ‘next’ button in your blog reader. ]
One of my team’s current projects at work is replacing a CORBA interface for managing video files with an interface involving sending XML over HTTP. We’ve looked at a few examples of XML/HTTP interfaces recently – we considered integrating a few areas of our software with a very simple hand-rolled RPC mechanism last year, and we’re also integrating a different part of our software with a SOAP interface right now. But one of my coworkers said “shouldn’t we look at REST?” in our team meeting on Thursday. And since all the cool bloggers are now spending their time talking about how REST is good and SOAP is bad, I thought that was a great idea: if nothing else, I was already rather embarrassed that I had no idea what REST meant, and it would give me an excuse to learn! So I spent a quite pleasant afternoon yesterday learning about it, and coming up with a RESTful version of the interface in question.
But before I explain what REST means, some Kealia history. The software-side founder of Kealia insisted that we follow a programming discipline he (I believe) invented called “attribute-oriented programming”. The idea here is that your object interfaces shouldn’t have any verbs: the interface should consist entirely of attribute getters and setters. So whenever you have a verb that you want to add to your interface, you have to think of a way to express this as changing the value of an attribute. Frequently, this isn’t too hard (though it’s still often distasteful): you might replace a schedule()
function with a nextTime()
setter. Other times, it’s much more of a stretch: sort()
is an example.
There are a few special exceptions allowed. The one that’s relevant to this discussion is that, if you want to add or remove something to/from a collection, then you should call a function named newXXX()
or deleteXXX()
. (And there are also some extra restrictions layered on top of this, but I won’t go into them here.)
Attribute-oriented programming turns out not to work very well. We still follow the rules, despite the departure of their proponent from active work on the project, because of a general feeling that we’d rather consistently follow a bad standard than mostly follow a bad standard but occasionally do whatever we feel like. (Though I personally would support a thoughtful effort to relax the rules in appropriate circumstances; it’s hard to make a good case for spending time on that, but every new hire is a reason to ask that question again.)
Despite my dislike for the attribute-oriented philosophy, there are some good things that go with it. We have a custom network layer for internal use: it’s specialized for sending out high-performance attribute updates. (Basically, Observer across the network; there are some other things grafted onto it, but I won’t go there.) Not great for a general purpose RPC system, but most of the time in this project, we don’t need a general purpose RPC system: instead, there are several crucial places in our code where we want to spit out lots of little state changes very quickly over the network, where this works quite well. It still takes a while for new hires to come up to speed, but this is one area where I think we made a good choice. (It’s not perfect – some of the details are pretty weird – but, well, if you’re waiting for perfection, you’ll have to wait a while.)
Which brings us to REST. REST (short for REpresentational State Transfer) is a philosophy that says that, if you’re trying to do RPCs over HTTP, you should work with the idioms of HTTP, instead of using it to tunnel general RPC ideas. To begin with, HTTP says that objects should be identified by URIs. (As opposed to, say, sticking an object identifier in the body of the message somewhere, or in some CGI parameter.) And HTTP provides you with four verbs: GET is the most common (your browser uses it every time it fetches a web page), POST is not infrequent (you use it when filling out forms), but there are also PUT and DELETE.
This turns out to map extremely well with attribute-oriented programming: GET and PUT are attribute readers and writers, POST and DELETE are the newXXX and deleteXXX on collections. (It seems that REST proponents are willing to use POST in a somewhat more flexible fashion than that, actually, but I won’t go into that now; certainly the sweet spot for POST seems to be the same.) It also maps extremely well to concepts in other areas: those of you who aren’t my coworkers have, I assume, never heard of attribute-oriented programming, but you’ve all heard of databases. And database people talk about Create, Read, Update, Delete (CRUD), which are POST, GET, PUT, and DELETE.
I don’t want to go into the details of the arguments, but the REST proponents sound reasonable to me: if you want to provide a programmatic interface for a service over the internet, you’ll have an easier time doing it if you can learn from the single most phenomenally successful example of such a beast. (Especially if you’re using that example’s underlying protocol to do your communication!) Network programming is different from and harder than writing a standalone program; learn from the lessons of the past, work with successful idioms, and you’ll avoid many mistakes and find it easier to grow an ecosystem around your service.
And certainly the interface that I’m thinking about at work fits fine within this framework. Let’s say that we have a URL http://foo.com/video/
that represents all the video stored on the server. Then, to upload some new video, do a POST to http://foo.com/video/
. This will return a URL representing the new file, say, http://foo.com/video/my-movie
. If someone else wants to learn something about the movie, that person (or program!) can do a GET to that URL or to some URL lying off of it: if you want to find its duration, for example, maybe GET from http://foo.com/video/my-movie/duration
, or maybe just GET from http://foo.com/video/my-movie
itself (which could return an XML object containing the duration as an attribute or an element).
(Incidentally, the details of that last example are what is currently giving me the most trouble. Which URL is the right one to use? If we go with the shorter one, is an attribute or an element more appropriate? For now, I’m leaning to initially using the shorter URL, and using an attribute, but I don’t see much different either way. I’m not immersed enough in XML to know when attributes are idiomatic and when elements are idiomatic in cases like this, alas…)
So that’s two of the verbs. If you then want to remove a video, just send a DELETE request to its URL. And if you want to change some attribute, do a PUT: if you made a typo in the director’s name in your initial POST, for example, you could PUT the new value to http://foo.com/video/my-movie/director
.
Fun stuff, this. I didn’t have to think much at all when designing the RESTful version of this interface: many of the decisions were already made for me, and I never had to fight REST, so I can be reasonably confident that other people will find the interface useable. Certainly the result is very simple; much more so than the SOAP example I was looking at. (Even at the surface level, though admittedly we’re solving a simpler problem; the actual underlying XML in that example made me rather nauseous.) The other model we’d been looking at (hand-rolled XML over HTTP, always using POST) was nice and simple, but the REST example is a little more coherent, and required us to make fewer decisions. (And I expect other people will find it a little easier to work with, at least if they’re not too RPC-immersed.)
The upshot is that I can follow certain discussions more intelligently than I could before, I have a good candidate for our new interface, and I have some new insights into the strengths and weaknesses of the way I’ve had to program for the last four years. (Speaking of which, yesterday was the three year anniversity of Kealia’s acquisition by Sun; I am amazed at how quickly the time has gone by.)
I leave you with a quote by Roy Fielding, the originator of REST, on SOAP (and other related protocols):
Post Revisions:
There are no revisions for this post.