Search code examples
scalacorslift

HTTP OPTIONS verb handling with LIFT


I'm using LIFT to serve a RESTful API, and I want this API to allow requests using CORS (Cross-Origin Resource Sharing) for POST. I do have CORS working with GET requests.

I'm having trouble because cross-origin POSTs first call OPTIONS on the given URL, and I haven't figured out how to accept OPTIONS requests with LIFT.

My question is: What do I need to mixin or write to my serve{} block such that I can allow the HTTP verb OPTIONS for a given path in LIFT?

Right now using curl I get:

curl -X OPTIONS http://localhost:8080/path => [404]

I'm using LIFT 2.4-M5 and Scala 2.9.1

EDIT: Based on pr1001's suggestion, I was trying to extend RestHelper like so:

import net.liftweb.http.provider._
import net.liftweb.http._

trait RestHelper extends net.liftweb.http.rest.RestHelper {
    protected object Options {
        // Compile error here with options_?
        // because net.liftweb.http.Req uses LIFT's RequestType
        def unapply(r: Req): Option[(List[String], Req)] =
            if (r.requestType.options_?) Some(r.path.partPath -> r) else None
    }
}

@serializable
abstract class RequestType extends net.liftweb.http.RequestType {
    def options_? : Boolean = false
}

@serializable
case object OptionsRequest extends RequestType {
    override def options_? = true
    def method = "OPTIONS"
}

object RequestType extends net.liftweb.http.RequestType {
    def apply(req: HTTPRequest): net.liftweb.http.RequestType = {
        req.method.toUpperCase match {
            case "OPTIONS" => UnknownRequest("OPTIONS")
            case _ => net.liftweb.http.RequestType.apply(req)
        }
    }

    def method = super.method
}

I feel like this is more work then I should need to do because I don't want to have to extend Req with my own RequestType impl.

I'm definitely on the lower level of skill set when it comes to Scala, so I'm hoping someone can provide a bit simpler solution because I'm sure there's something I'm missing.


Solution

  • Are you using RestHelper? If so you'd specify the type of request you want to respond to and return a LiftResponse. There's no OptionRequest in Lift (yet) to use in the partial function you pass to serve() but you should be able to extend RequestType with your own version. Using UnknownRequest – as in UnknownRequest("OPTION") – might also do the trick.

    This might also be worth bringing up on the mailing list, as CORS support would be a useful addition...