There has been a lot of buzz over the past few days about ASP.NET MVC allowing developers to create RESTful URLs. This turned out to be very good timing since I was implementing RESTful URLs without first realizing it in MonoRail last week.
I had to give a business partner two links to our new online service, one for each screen mode the partner's web device supported: splitscreen and fullscreen. This got me thinking about the URLs I was providing, since I was essentially etching the URL in stone; I wanted to make sure they looked professional and provided maximum flexibility in the future. It also got me wondering if I couldn't add additional information into the URL; information that in the past I would have stuck in a cookie or in a session.
At first I put this extra data in the session, but then I started thinking about: session time out, load balancing, SQL Server DB, and scalability. Cookies might be better, but then I thought how the browser on these devices immediately asks you if you want to store a cookie - bad first impression. It seemed the answer was to use the querystring and pass state around from one page to the next on the querystring, but I hated the idea of passing around a few values on every single page request. This seemed fragile and made every page URL ugly and long.
I already knew that you generally want to use directories, or resources, over querystring parameters for web search engine optimization, but then I realized that using resources instead of querystring parameters is also more organized and user friendly. Here's an example of two URLs, one using a querystring, and the other using a REST style resource URL.
http://sneal.net/fullscreen/categories/category1/page1
http://sneal.net/categories.rails?screenMode=fullscreen&category=1&page=1
I think its pretty obvious that the first (REST style) URL is much better for several reasons:
- Easier to read, it's essentially just a directory path.
- Easy to remember, it avoids strange symbols and is shorter.
- Provides a nice structure to the data: categories -> 1st category -> 1st page.
- It's discoverable. Its pretty obvious what you can type in to go to page2 etc.
Another benefit is that links into your web application aren't tied to a particular technology or platform. I've already experienced this at GalleryPlayer when we wanted to change some static HTML content into dynamic ASP.NET pages - external URLs weren't just looking for a resource, but they were explicitly looking for a static HTML page. If we had implemented REST style URLs from the very beginning using URL rewriting, any external links could have been using a technology agnostic URL instead of a specific one tied to static HTML.
For example, I can point people to http://sneal.net/blog/somepost, rather than http://sneal.net/blog/blog.aspx?post=somepost. If later on I decided to switch from dasBlog to a ROR based blog engine running on Linux, I could do that without anyone being the wiser. The blog.aspx link would be much more difficult to change the underlying technology to ROR since the link includes the resource 'blog' and the view implementation type, 'aspx'.
Lets not forget what URL stands for: Uniform Resource Locator. In the end the consumer of your data shouldn't really care how you produce the results, whether you're using ASP.NET, MonoRail, ROR, PHP, or JSP. The only thing the consumer should care about is the data your service, or web page, is providing - and where to find it at. With an MVC framework like MonoRail, ROR, or ASP.NET MVC, URL routing couldn't be easier.
As K Scott Allen said, "The [ASP.NET] MVC framework is, I believe, about putting control in the hands of a web developer. Control over the routing of HTTP requests to components. Control over selecting the view. Control over state management, and control over the outgoing HTML." I couldn't agree more. URL routing/rewriting gives you a flexible abstraction layer between your URLs and your resource implementations.
In my next post I hope to show how I avoided session state and cookies by using REST style URLs with MonoRail.