This is my Blog.

It's full of opinions on a wide range of stuff.

HTTP Dispatch Guards in Lift using PartialFunction

There are many little known features within the Lift code base and one that i've been meaning to blog about for quite some time is the ability ot use partial functions as guards for HTTP dispatch.

Let's assume that your system requires some state to be set, like a session variable to ensure the user has logged in before they can access other parts of the service. The following example shows you you can implement a simple partial function to act as a guard.

What's the goal?

The aim is to be able to define your services like so:

LiftRules.dispatch.append(withAuthentication guard Service)

This gives you a fairly readable API that even with little knowledge of the underlying API you can see that you must have an authenticated session. In this super simple case, I'll just implement authentication as a Boolean in a SessionVar, but you get the point.

The Service

Consider this service definition:

import net.liftweb.http.rest.RestHelper
import net.liftweb.http.{PlainTextResponse}

object Service extends RestHelper { 
  serve {
    case "protected" :: Nil Get _ => 
      PlainTextResponse("Ohh, secret")
  }
}

This is a super simple service using HTTP dispatch in Lift. Let's then define the dummy "login" url. In practice this would actually be some kind of bonified authentication but for this example it will suffice.

import net.liftweb.http.rest.RestHelper
import net.liftweb.http.{SessionVar,OkResponse}

object Security extends RestHelper {
  serve {
    case "login" :: Nil Get _ => 
      LoggedIn(true)
      OkResponse()
  }
}

object LoggedIn extends SessionVar(false)

As you can see, simply hitting the URL /login will set the session to be logged in. Completely useless for production, but it serves my means here.

The Boot Configuration

Finally, now you have the services setup its time to write it all together within the Boot class.

import net.liftweb.http.{LiftRules,Req}
import net.liftweb.util.Helpers._ 
import sample.lib.{Security,Service,LoggedIn}

class Boot {
  def boot {
    val withAuthentication: PartialFunction[Req, Unit] = { 
      case _ if LoggedIn.is => 
    }

    LiftRules.dispatch.append(Security)
    LiftRules.dispatch.append(withAuthentication guard Service)
  }
}

The key here is the import of Helpers._ to provide the implicit functions to enable guard to be called on the withAuthentication partial function, and the withAuthentication value simply passes all cases to an if statement that accesses the value of the SessionVar. Pretty simple, eh?

Enjoy. All the code for this sample can be found "here":https://github.com/timperrett/lift-dispatch-guard

blog comments powered by Disqus