Created
January 13, 2011 12:57
-
-
Save ssuravarapu/777820 to your computer and use it in GitHub Desktop.
For Conditional GET and PUT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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