package code package lib import model._ import net.liftweb._ import common._ import http._ import rest._ import json._ import scala.xml._ /** * A simple example of a REST style interface * using the basic Lift tools */ object BasicWithHelper extends RestHelper { /* * Serve the URL, but have a helpful error message when you * return a 404 if the item is not found */ serve { case "simple3" :: "item" :: itemId :: Nil JsonGet _ => for { // find the item, and if it's not found, // return a nice message for the 404 item <- Item.find(itemId) ?~ "Item Not Found" } yield item: JValue case "simple3" :: "item" :: itemId :: Nil XmlGet _ => for { item <- Item.find(itemId) ?~ "Item Not Found" } yield item: Node } serve { // Prefix notation case JsonGet("simple4" :: "item" :: Item(item) :: Nil, _) => // no need to explicitly create a LiftResponse // Just make it JSON and RestHelper does the rest item: JValue // infix notation case "simple4" :: "item" :: Item(item) :: Nil XmlGet _ => item: Node } // serve a bunch of items given a single prefix serve ( "simple5" / "item" prefix { // all the inventory case Nil JsonGet _ => Item.inventoryItems: JValue case Nil XmlGet _ => Item.inventoryItems: Node // a particular item case Item(item) :: Nil JsonGet _ => item: JValue case Item(item) :: Nil XmlGet _ => item: Node }) /** * Here's how we convert from an Item * to JSON or XML depending on the request's * Accepts header */ implicit def itemToResponseByAccepts: JxCvtPF[Item] = { case (JsonSelect, c, _) => c: JValue case (XmlSelect, c, _) => c: Node } /** * serve the response by returning an item * (or a Box[Item]) and let RestHelper determine * the conversion to a LiftResponse using * the itemToResponseByAccepts partial function */ serveJx[Item] { case "simple6" :: "item" :: Item(item) :: Nil Get _ => item case "simple6" :: "item" :: "other" :: item :: Nil Get _ => Item.find(item) ?~ "The item you're looking for isn't here" } /** * Same as the serveJx example above, but we've * used prefixJx to avoid having to copy the path * prefix over and over again */ serveJx[Item] { "simple7" / "item" prefixJx { case Item(item) :: Nil Get _ => item case "other" :: item :: Nil Get _ => Item.find(item) ?~ "The item you're looking for isn't here" } } }
/** * A simple example of a REST style interface * using the basic Lift tools */ object BasicWithHelper extends RestHelper {
LiftRules.statelessDispatchTable.append(BasicWithHelper)
serve { case "simple3" :: "item" :: itemId :: Nil JsonGet _ => for { // find the item, and if it’s not found, // return a nice message for the 404 item <- Item.find(itemId) ?~ "Item Not Found" } yield item: JValue case "simple3" :: "item" :: itemId :: Nil XmlGet _ => for { item <- Item.find(itemId) ?~ "Item Not Found" } yield item: Node }
case "simple3" :: "item" :: itemId :: Nil JsonGet _ =>
for { // find the item, and if it’s not found, // return a nice message for the 404 item <- Item.find(itemId) ?~ "Item Not Found" } yield item: JValue
dpp@raptor:~/proj/simply_lift/samples/http_rest$ curl http://localhost:8080/simple3/item/12999 Item Not Found dpp@raptor:~/proj/simply_lift/samples/http_rest$ curl http://localhost:8080/simple3/item/1234 { "id":"1234", "name":"Cat Food", "description":"Yummy, tasty cat food", "price":4.25, "taxable":true, "weightInGrams":1000, "qnty":4 }
case "simple3" :: "item" :: itemId :: Nil XmlGet _ => for { item <- Item.find(itemId) ?~ "Item Not Found" } yield item: Node
dpp@raptor:~/proj/simply_lift/samples/http_rest$ curl -i -H "Accept: application/xml" http://localhost:8080/simple3/item/1234 HTTP/1.1 200 OK Expires: Wed, 9 Mar 2011 01:48:38 UTC Content-Length: 230 Cache-Control: no-cache; private; no-store Content-Type: text/xml; charset=utf-8 Pragma: no-cache Date: Wed, 9 Mar 2011 01:48:38 UTC X-Lift-Version: Unknown Lift Version Server: Jetty(6.1.22) <?xml version="1.0" encoding="UTF-8"?> <item> <id>1234</id> <name>Cat Food</name> <description>Yummy, tasty cat food</description> <price>4.25</price> <taxable>true</taxable> <weightInGrams>1000</weightInGrams> <qnty>4</qnty> </item>
/** * Convert an item to XML */ implicit def toXml(item: Item): Node = <item>{Xml.toXml(item)}</item> /** * Convert the item to JSON format. This is * implicit and in the companion object, so * an Item can be returned easily from a JSON call */ implicit def toJson(item: Item): JValue = Extraction.decompose(item)
serve { // Prefix notation case JsonGet("simple4" :: "item" :: Item(item) :: Nil, _) => // no need to explicitly create a LiftResponse // Just make it JSON and RestHelper does the rest item: JValue // infix notation case "simple4" :: "item" :: Item(item) :: Nil XmlGet _ => item: Node }
// serve a bunch of items given a single prefix serve ( "simple5" / "item" prefix { // all the inventory case Nil JsonGet _ => Item.inventoryItems: JValue case Nil XmlGet _ => Item.inventoryItems: Node // a particular item case Item(item) :: Nil JsonGet _ => item: JValue case Item(item) :: Nil XmlGet _ => item: Node })
dpp@raptor:~/proj/simply_lift/samples/http_rest$ curl http://localhost:8080/simple5/item [{ "id":"1234", "name":"Cat Food", "description":"Yummy, tasty cat food", "price":4.25, "taxable":true, "weightInGrams":1000, "qnty":4 }, ... ,{ "id":"1237", "name":"Sloth Food", "description":"Slow, slow sloth food", "price":18.33, "taxable":true, "weightInGrams":750, "qnty":62 }] dpp@raptor:~/proj/simply_lift/samples/http_rest$ curl http://localhost:8080/simple5/item/1237 { "id":"1237", "name":"Sloth Food", "description":"Slow, slow sloth food", "price":18.33, "taxable":true, "weightInGrams":750, "qnty":62 }
implicit def itemToResponseByAccepts: JxCvtPF[Item] = { case (JsonSelect, c, _) => c: JValue case (XmlSelect, c, _) => c: Node }
serveJx[Item] { case "simple6" :: "item" :: Item(item) :: Nil Get _ => item case "simple6" :: "item" :: "other" :: item :: Nil Get _ => Item.find(item) ?~ "The item you’re looking for isn’t here" }
dpp@raptor:~/proj/simply_lift/samples/http_rest$ curl http://localhost:8080/simple6/item/1237 { "id":"1237", "name":"Sloth Food", "description":"Slow, slow sloth food", "price":18.33, "taxable":true, "weightInGrams":750, "qnty":62 } dpp@raptor:~/proj/simply_lift/samples/http_rest$ curl -H "Accept: application/xml" http://localhost:8080/simple6/item/1234 <?xml version="1.0" encoding="UTF-8"?> <item> <id>1234</id> <name>Cat Food</name> <description>Yummy, tasty cat food</description> <price>4.25</price> <taxable>true</taxable> <weightInGrams>1000</weightInGrams> <qnty>4</qnty> </item>
serveJx[Item] { "simple7" / "item" prefixJx { case Item(item) :: Nil Get _ => item case "other" :: item :: Nil Get _ => Item.find(item) ?~ "The item you’re looking for isn’t here" } }
(C) 2012 David Pollak