Article: Multi-format REST services with Lift

6 views
Skip to first unread message

Timothy Perrett

unread,
Mar 29, 2010, 1:06:22 PM3/29/10
to Lift
All,

I just posted a new article on creating multi format web services with
Lift: http://is.gd/b5o9D

Enjoy.

Cheers, Tim

Marius

unread,
Mar 29, 2010, 1:10:37 PM3/29/10
to Lift
Great stuff Tim !

Timothy Perrett

unread,
Mar 29, 2010, 2:57:52 PM3/29/10
to Lift
Thanks Marius!

What do you think of the general idiom?

Cheers, Tim

Marius

unread,
Mar 29, 2010, 3:11:33 PM3/29/10
to Lift
It's certainly a way to do it but sometimes the actual LiftResponse
needs to incorporate response headers computed based on request
headers etc. It really depends on the application/use-case needs.
Sometimes response mime-type is determined based on request Accept
header. There are numerous cases that lead to different patterns of
abstraction.

Br's,
Marius

Timothy Perrett

unread,
Mar 29, 2010, 3:26:43 PM3/29/10
to Lift
Right, I tottaly agree. Those services are the most basic ones from an
application im working on which do exactly what you say and are more
specific about Req parameters and other environmental factors.

I guess the main thing here is the use of function passing - whilst
your experienced scala geek would know to use them, most new comers
would probably implement something more OO and its that which I really
wanted to get across.

Cheers, Tim

harryh

unread,
Mar 29, 2010, 4:10:41 PM3/29/10
to Lift
FWIW, an alternate approach (in use at foursquare):

def dispatch: LiftRules.DispatchPF = {
case req@Req(List("api", "v1", "cities"), _, GetRequest) => () =>
wrap(req, cities)
// many other cases for other endpoints
}

def wrap(req: Req, f: (Req, Box[User]) => Elem) = {
val currentUser = // determine currentUser from Req
val xml = f(req, currentUser)

req.path.suffix match {
case "xml" => {
XmlResponse(Utility.trim(xml), code)
}
case "json" => {
JsonCodeResponse(xmlToJson(xml), code)
}
case _ => XmlResponse(<error>Invalid API Suffix</error>, 501)
}
}

def xmlToJson(xml: Elem): JsExp = {
// code to map XML responses to JSON responses. Handles tricky
things like always returning
// js arrays for some fields even if only 1 element appears in the
XML
}

def cities(req: Req, currentUser: Box[User]) = {
val cities = // load city objects from datastore
<cities>{cities.flatMap(GenXml(_))}</cities>
}

If I was doing things over(1) I'd invert it and always generate the
json and convert to XML as necessary. It's this way for historical
reasons.

-harryh

Actually, I'd probably just drop XML support entirely. JSON is better
in basically every way.

Timothy Perrett

unread,
Mar 29, 2010, 4:36:33 PM3/29/10
to lif...@googlegroups.com
Harry,

I actually considered the JSON route and converting it to XML, but for several reasons it was not for me. The double serialisation didn't sit right with me for some reason (it felt a bit wrong), either way - JSONtoXML or XMLtoJSON - and for my particular usage I tend to prefer finite control over the responses rather than just serialising and flushing to a response.

But your right, this is of course another possible route - as with all things in Lift, there are a lot of ways to skin the proverbial cat. For the most part I think the difference is stylistic and use case specific... double serialisation would work for most apps though for sure, but if you need stuff like AMQP or what not it might fall down a little.

Interesting discussion never the less!

Cheers, Tim

> --
> You received this message because you are subscribed to the Google Groups "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
>
>

harryh

unread,
Mar 29, 2010, 4:41:52 PM3/29/10
to Lift
> But your right, this is of course another possible route - as with all things in Lift, there are a lot of ways to skin the proverbial cat.

Oh ya, totally agree there are issues with double serialization
(particularly the XML -> JSON route I'm stuck in). Def would vary
from app to app which way is more desirable.

-harryh

Timothy Perrett

unread,
Mar 29, 2010, 4:54:32 PM3/29/10
to lif...@googlegroups.com
Im actually experimenting with an asynchronous domain model built with akka and lift as a service tier... thats why the code in my article is all stateless so it can be clustered and scale with akka.

I wonder if that kind of design would be good for you guys considering where your traffic is going :-D

Cheers, Tim

Reply all
Reply to author
Forward
0 new messages