Skip to content

Instantly share code, notes, and snippets.

@ssuravarapu
Created January 13, 2011 12:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ssuravarapu/777820 to your computer and use it in GitHub Desktop.
Save ssuravarapu/777820 to your computer and use it in GitHub Desktop.
For Conditional GET and PUT
package code.service
import xml.{Elem, Node}
import net.liftweb.http._
import rest.RestHelper
import provider.HTTPCookie
import net.liftweb.common.{Empty, Full}
import code.model.Product
object WebService extends RestHelper {
serve {
case r @ Req("webservices" :: "product" :: id :: _, _, GetRequest) => {
val reqETag = r.header("If-None-Match") openOr ""
val product = Product.findByKey(id.toLong)
product match {
case Full(x) => {
val resourceETag = x.updatedAt.toLong.toString
compareETags(reqETag, resourceETag) match {
case true => NotModifiedResponse(resourceETag)
case false => XmlResponse(toXml(x), resourceETag)
}
}
case _ => NotFoundResponse("Resource not found")
}
}
case r @ Req("webservices" :: "product" :: id :: _, _, PutRequest) => {
def updateResource(id: String, r: Req): LiftResponse = {
val reqETag = r.header("If-Match") openOr ""
val product = Product.findByKey(id.toLong)
product match {
case Full(x) => {
compareETags(reqETag, x.updatedAt.toLong.toString) match {
case true => {
save(r.xml.open_!, x)
NoContentResponse(x.updatedAt.toLong.toString)
}
case false => PreConditionFailedResponse(x.updatedAt.toLong.toString,
"Update failed. Resource state changed.")
}
}
case _ => NotFoundResponse("Resource not found")
}
}
r.xml_? match {
case true => updateResource(id, r)
case false => NotFoundResponse("Resource not found")
}
}
}
def toXml(product: Product) = {
<product>
<itemNumber>{product.itemNumber.is}</itemNumber>
<name>{product.name.is}</name>
<price>{product.price.is}</price>
<quantity>{product.quantity.is}</quantity>
</product>
}
def save(rootNode: Elem, product: Product) = {
product.name((rootNode \ "name").text)
product.price(BigDecimal((rootNode \ "price").text))
product.quantity((rootNode \ "quantity").text.toInt)
product.save
}
def compareETags(reqETags: String, respETag: String) = reqETags split(",") map (_.trim) contains("\"" + respETag + "\"")
}
class XmlResponse(val xml: Node, val code: Int, val mime: String, val _headers: List[(String, String)],
val cookies: List[HTTPCookie]) extends NodeResponse {
def docType = Empty
def out: Node = xml
def headers = _headers
}
object XmlResponse {
def apply(xml: Node, eTag: String) =
new XmlResponse(xml, 200, "application/xml", ("Content-Type" -> "application/xml") :: "ETag" -> ("\"" + eTag + "\"") :: Nil, Nil)
}
case class NoContentResponse(eTag: String) extends LiftResponse with HeaderDefaults {
def toResponse = InMemoryResponse(Array(), "ETag" -> ("\"" + eTag + "\"") :: headers, cookies, 204)
}
case class NotModifiedResponse(eTag: String) extends LiftResponse with HeaderDefaults {
def toResponse = InMemoryResponse(Array(), "ETag" -> ("\"" + eTag + "\"") :: headers, cookies, 304)
}
case class PreConditionFailedResponse(eTag: String, msg: String) extends LiftResponse with HeaderDefaults {
def toResponse = InMemoryResponse(msg.getBytes("UTF-8"), "ETag" -> ("\"" + eTag + "\"") :: headers, cookies, 412)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment