Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions contributors.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,9 @@ Paweł Mruk

### Email: ###
mroocoo at gmail dot com

### Name: ###
Riccardo Sirigu

### Email: ###
me@riccardosirigu.com
2 changes: 2 additions & 0 deletions web/webkit/src/main/scala/net/liftweb/http/Req.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,8 @@ class Req(val path: ParsePath,

val post_? = requestType.post_?

val patch_? = requestType.patch_?

val get_? = requestType.get_?

val put_? = requestType.put_?
Expand Down
7 changes: 7 additions & 0 deletions web/webkit/src/main/scala/net/liftweb/http/RequestType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ abstract class RequestType extends Serializable{

def put_? : Boolean = false

def patch_? : Boolean = false

def delete_? : Boolean = false

def options_? : Boolean = false
Expand All @@ -51,6 +53,10 @@ case object PutRequest extends RequestType {
override def put_? = true
val method = "PUT"
}
case object PatchRequest extends RequestType{
override def patch_? : Boolean = true
val method: String = "PATCH"
}
case object DeleteRequest extends RequestType {
override def delete_? = true
val method = "DELETE"
Expand All @@ -68,6 +74,7 @@ object RequestType {
case "POST" => PostRequest
case "HEAD" => HeadRequest
case "PUT" => PutRequest
case "PATCH" => PatchRequest
case "DELETE" => DeleteRequest
case "OPTIONS" => OptionsRequest
case meth => UnknownRequest(meth)
Expand Down
51 changes: 51 additions & 0 deletions web/webkit/src/main/scala/net/liftweb/http/rest/RestHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,43 @@ trait RestHelper extends LiftRules.DispatchPF {
def body(r: Req): Box[T]
}


/**
* A trait that defines the TestPatch extractor. Is
* the request a PATCH, has JSON or XML data in the post body
* and something that expects JSON or XML in the response.
* Subclass this trait to change the behavior
*/
protected trait TestPatch[T] {
/**
* Test to see if the request is a PATCH, has JSON data in the
* body and expecting JSON in the response.
* The path, JSON Data and the Req instance are extracted.
*/
def unapply(r: Req): Option[(List[String], (T, Req))] =
if (r.patch_? && testResponse_?(r))
body(r).toOption.map(t => (r.path.partPath -> (t -> r)))
else None


def testResponse_?(r: Req): Boolean

def body(r: Req): Box[T]
}

/**
* The stable identifier for JsonPatch. You can use it
* as an extractor.
*/
protected lazy val JsonPatch = new TestPatch[JValue] with JsonTest with JsonBody

/**
* The stable identifier for XmlPatch. You can use it
* as an extractor.
*/
protected lazy val XmlPatch = new TestPatch[Elem] with XmlTest with XmlBody


/**
* a trait that extracts the JSON body from a request It is
* composed with a TestXXX to get the correct thing for the extractor
Expand Down Expand Up @@ -290,6 +327,20 @@ trait RestHelper extends LiftRules.DispatchPF {

}

/**
* An extractor that tests the request to see if it's a PATCH and
* if it is, the path and the request are extracted. It can
* be used as:<br/>
* <pre>case "api" :: id :: _ Patch req => ...</pre><br/>
* or<br/>
* <pre>case Patch("api" :: id :: _, req) => ...</pre><br/>
*/
protected object Patch {
def unapply(r: Req): Option[(List[String], Req)] =
if (r.patch_?) Some(r.path.partPath -> r) else None

}

/**
* An extractor that tests the request to see if it's a DELETE and
* if it is, the path and the request are extracted. It can
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,17 @@ class RestHelperSpec extends WebSpec(RestHelperSpecBoot.boot _) {

"RestHelper" should {
val testOptionsUrl = "http://foo.com/api/info"
val testPatchUrl = "http://foo.com/api/patched"
val testFutureUrl = "http://foo.com/api/futured"

val testOptionsReq = new MockHttpServletRequest(testOptionsUrl){
method = "OPTIONS"
}

val testPatchReq = new MockHttpServletRequest(testPatchUrl){
method = "PATCH"
}

val testFutureReq = new MockHttpServletRequest(testFutureUrl){
method = "GET"
}
Expand All @@ -41,6 +46,10 @@ class RestHelperSpec extends WebSpec(RestHelperSpecBoot.boot _) {
}
}

"set PATCH method" withReqFor testPatchReq in { req =>
req.patch_? must_== true
}

"respond async with something that CanResolveAsync" withReqFor testFutureReq in { req =>
val helper = FutureRestSpecHelper()

Expand Down Expand Up @@ -68,6 +77,7 @@ class RestHelperSpec extends WebSpec(RestHelperSpecBoot.boot _) {
object RestHelperSpecRest extends RestHelper {
serve {
case "api" :: "info" :: Nil Options req => OkResponse()
case "api" :: "patched" :: Nil Patch req => OkResponse()
}
}

Expand Down