As a Scala enthusiast I'm currently evaluating Lift, particularly the aspect of its REST support. This could become a series of posts on the topic as I try to understand the framework better and may be subject it to a litmus test proposed by Stefan Tilkov. Of course, I will not be making a judgment call whether the framework is RESTful or not as I don't want to get into a dogmatic discussion!
So far I like what I see, it is a productive framework with a nice set of features (and has cherry-picked some best ideas from other frameworks too), and what else it's Scala-based (my current favorite language).
Setup
Getting started instructions on Liftweb's wiki worked perfectly fine for me. I used instructions for Maven and I'm using Scala 2.8.
URI Matching
RESTHelper is the trait that you may want to extend for building your REST-based web services. Lift's URI dispatch follows the templating approach in which you would leave part of the URIs to be filled by the clients before they are submitted. For example, id can be sent dynamically by the user: http://example.org/api/user/{id}
The following block of code can take care of the above URI matching ...
the List of strings are the tokens after each "/" (forward slash) in the URI. The above code indicates that a GET request can handle that specific URI pattern. And when such a pattern is encountered invoke the method userDetails. If a URI is encountered as http://example.org/api/user/101, 101 is bound to id variable.
Box[LiftResponse] is the return type that's expected. Box goes by the same notion as Option in Scala. When you have stuff to return you would respond with Full(LiftResponse) and Empty when there is no response. So here is an example of how you can URI match and dispatch for a sample CRUD (I'm using simple User account management).
Ideally I would like to write this in a single case block without breaking into multiple units as I did above. When I add more than three case statements of this complexity (which is not that much, IMO) Scala compiler takes way too long and eventually gives up with an OffsetTooBigException. This issue is in bug tracker for a while now, and the above approach of splitting the matchers into multiple units is based on the workaround suggested there.
The pattern matching is flexible and works great for multiple tokens too. Something like http://example.org/user/{userId}/address/{addrId} can be extracted using a very similar pattern like above with values for userId and addrId binding to their corresponding variables.
Here is an excellent article on Scala's partial functions and pattern matching that you may find it useful in the context of this discussion.
Content Negotiation
Content negotiation is one of the core concepts of RESTful systems where a client can indicate which media type(s) it prefers. Also within the media types it can specify the order of preference. Client does this by using Accept header. For example, consider the following Accept header --
Accept: application/xml;q=0.8, application/json;q=0.9
It indicates to the server a) it can accept XML and JSON formats and b) it prefers JSON over XML (by providing higher value for 'q' parameter. q value ranges from 0.0 to 1.0, higher value indicates more preference).
Ok, so how does Lift fares in this area? Mixed results --
- It recognizes which media type to serve by the Accept header. So for example
Accept:application/jsonheader from the client is matched tocase "api" :: "user" :: id :: _ XmlJson _ => ... - Similarly for XML, an accept header with
text/xmlis matched toXmlGetmethod fine. One issue that I encountered here is it only recognizestext/xmlas XML media type and notapplication/xml.application/xmlis actually preferable totext/xml, generally speaking. One reason on top of my head is text/* media types ignore the encoding specified in the content, in this case if you declare a specific encoding (e.g: UTF-8) in the XML declaration header it will be ignored. - It doesn't respect the q parameter value. So in the above example,
Accept: text/xml; q=0.8, application/json;q=0.9it still serves the client XML as it only looks for iftext/xmlis present in the header.
So let's look at Tilkov's first question in the list:
Does the framework respect that an HTTP message does not only consist of a URI? I.e., is dispatch done at least based on the HTTP verb, the URI, the Content-type and Accept headers?
My answer, at this point: Yes dispatch works great in terms of -- HTTP verb, the pattern matching URI templates and Accept headers (partially). Lift has to get its act together in further tightening its content negotiation support.
[I would love to contribute some patches for this and more (like hypermedia support, will elaborate it in the future posts). Lift folks, you have a volunteer here!]
Stay tuned!
Update: Follow-up is posted here: Lift and Content Negotiation

Follow on Twitter
Surya Suravarapu Reply:
August 4th, 2010 at 10:24 am
Two points here:
1. I actually like JAX-RS and I’ve worked with two of its implementations – Jersey and RestEasy. I have written my experiences in a couple of posts earlier, the one on CRUD is here: http://www.suryasuravarapu.com/2009/03/rest-crud-with-jax-rs-jersey.html
2. As far as Lift is concerned, I like the framework, quite a bit, as a web framework, in general, not just for web services support. As a Scala enthusiast I’m interested in a Scala-based web framework. Also as an advocate of REST-based web services I’m currently evaluating that aspect of the framework.
As I proceed, I also intend to do my bit improving the framework in the way of contributions.