OpenRasta, or “How to speak REST”
The hillbilly is on a new project. Well actually, I’m on two new projects but I’m still working on how to Code Better on the one that involves stored procs in Oracle, a web site project (vs. web application project), a data access layer consisting entirely of static methods, and no unit tests except on the domain objects themselves. Suffice it to say that “maintainability” means very different things to different people.
The other project has led me to investigate REST (or, more accurately, ReST but that’s the last time I’ll call it that because that looks too alt even for my tastes). The bulk of the work for the application is going to be done via JavaScript calls to services. So in my attempt to hammer that screw with ASP.NET MVC, my first reaction was: S#arp Architecture with judicious use of JsonResult.
Luckily, my partner-in-crime is a little more rounded, and politely, but firmly, guided me away from MVC saying, “I ain’t building this app with that whore makin’ the rounds on every blog short of Wil Wheaton’s”, or something to that effect. Instead, he said a RESTful architecture may be more suitable for our goals. So I set about the task of investigating it.
There is enough out there on REST that you can find on your own, starting with the Wikipedia page. But my English teacher always told me to understand something, you should put it in your own words. In keeping with that, REST is, to my thinking, a way of architecting your application based on resources and how they are accessed. Strictly speaking, it is implementation-agnostic but for my purpose, I find it useful to tie it to HTTP because that’s the canonical example and because, well, I’m building a web app.
With respect to HTTP, REST de-emphasizes the URL (or, apparently more accurately, the URI) as the be-all and end-all of how to perform some action, like getting a list of possible moonshine bases or adding a new store to your designer clothing empire. Instead, the URL is a placeholder, basically a way of accessing the resource. What you want to do with it depends on other factors, like the HTTP verb used to get it and the data sent to the page in the HTTP header.
For example, http://roadkilldiner.com/menuItem/3 could be a valid URL. But what it does depends on how you access it. If you use a GET verb, then you want to get the details of the menu item with ID 3. If you use a PUT (or POST, this is still kind of fuzzy to me), you would update it (or possibly add a new one with an ID 3, I think; hopefully some RESTful commenters will clarify that for me). In this case, you’d have to provide some more information to the URL in the header. Using a DELETE verb will automatically update it to the latest version of your application. I’m kidding, of course, you all know what DELETE will do.
Incidentally, none of this says anything on how the menu item will be rendered when you do a GET. Maybe it will be XML, maybe JSON, maybe some proprietary format. When you make a request, part of the information you provide is how you want the item to be returned to you. If memory serves, I think the ACCEPT HTTP header determines this.
Furthermore, HTTP defines a whole whack of return codes that we typically ignore. OK and PageNotFound are no strangers but there is also MethodNotAllowed, Created, and a bunch of others. Typically, I don’t pay any attention to them but in REST, this things have meaning and are part of the implementation.
So to sum up, the URL is just the starting point, identifying the resource with which you want to work. What you do with it depends on a host of other data provided with the request and the status code that is returned. With that bit of understanding out of the way, my next step was to see how this could potentially be implemented in .NET. (Comment if you want on the futility of doing this in .NET, I’m already neck deep in new concepts on this project. I need C# as my safety blanket.)
My first stop was still MVC and the SimplyRestful routing with MvcContrib. But that didn’t sit too well with me. It is, after all, a model-view-controller and we wouldn’t have a lot of need for the view part. In short, REST feels like an afterthought with respect to MVC.
My cohort turned me on to WCF Rest Starter Kit and we were duly impressed at the veritable fountain of information available, particularly in the form of screencasts. After checking out a couple and playing with some demo services, this looked like a step in the right direction. It seems to gel with my understanding of REST, such as it is. HTTP verbs, different content types, a URL templating mechanism, all of this appears to be handled in some form or another.
But in the back of my mind, a little voice kept saying “OpenRasta”, a framework I had followed to varying degrees over the last year or so. Based on the documentation, it seemed to be a different form of MVC implementation but with different syntax and better support for different content types.
Let me say this up front, and I’ve told the project owner, Sebastien Lambla, the same thing, this documentation is to the detriment of the project itself because the demonstration he graciously gave (at my request, I should note) was impressive as hell. And it may be too soon to tell, but it looks much, much better than the WCF implementation. Admittedly, I had originally set up the demo primarily in order to answer some general REST questions because Sebastien always seemed to be talking about it and he’s a bright guy. I had a vague idea of what OpenRasta did but I was skeptical that it could replace the sheer magnitude of marketing force behind WCF REST Starter Kit.
I’ll give you some samples from memory. Sebastien will likely chime in if they’re wrong. The following will return a Json representation of a MenuItem for a GET request:
public class MenuItemHandler { public MenuItem Get( int id ) { return new MenuItem { Id = id, OriginalSpecies = "Raccoon" }; } }
That's it. Provided you do the proper configuration, of course, which is similar to setting up routes in MVC. But the highlights are:
- Class doesn’t need to inherit from a base class
- No need to manually serialize the object
- No need to manually specify the HTTP verb
- No need to specify the content type at all
Now, if you want to also return the object in XML format, here is what the code would then look:
// See above code
That is, your implementation code doesn't change. In the configuration, you tell it that you’d also like to be able to handle XML requests and that’s it. The framework does everything else for you. Provided you specify the content-type in the ACCEPT header, it will use the same method to return the object in JSON or XML format.
It gets better. If you want to return this in an HTML page that spits out all the properties, again, nothing changes. You change the configuration so that it accepts HTML requests, and you set up a view for it (similar to MVC), and that’s it.
By the way, this is only one alternative. If you want more control over your status code, you can do it in a slightly more MVC-ish way:
public class MenuItemHandler { public OperationResult Get( int id ) { return new OperationResult.OK { ResponseResource = new MenuItem { Id = id, OriginalSpecies = "Raccoon" } }; } }
I’m starting to get into areas where I may not be doing the syntax justice but the idea is the same. You can specify the exact HTTP status code you’d like returned with each method.
Handling the other HTTP verbs is a simple matter of adding the methods:
public class MenuItemHandler { public MenuItem Get( int id ) { return new MenuItem { Id = id, OriginalSpecies = "Raccoon" }; } public OperationResult Post( MenuItem menuItem ) { // Update the menu item return new OperationResult.Created { ResponseResource = menuItem }; } }
All in all, colour us both very impressed. As I’ve mentioned, documentation is light and the beta and open-source nature of it may give one the willies. But given that we are both very new to REST, we got a nice warm fuzzy feeling that OpenRasta would lead us down the right path without: a) getting in our way, or b) hiding the details of REST that we need to understand to use it properly. Will report back after using it more but as it stands now, we’re basking in the afterglow of a demo gone right.
Kyle the Dazzled