playframework/playframework — pull request #1986 by dylex (2013-11-07 14:27:38+00:00)
Title: Generalize ActionBuilder by parameterizing over Request type

I love the new ActionBuilder in play 2.2, but I want even more. I want (and in fact am now using) something like this:

```scala
/** A generic version of ActionBuilder parameterized over the request type. */
trait ActionFunction[-R[_],P[_]] {
parent =>
def invokeBlock[A](request : R[A], block : P[A] => Future[SimpleResult]) : Future[SimpleResult]

/** Compose this ActionFunction with another. */
def ~>[Q[_]](child : ActionFunction[P,Q]) : ActionFunction[R,Q] = new ActionFunction[R,Q] {
def invokeBlock[A](request : R[A], block : Q[A] => Future[SimpleResult]) =
parent.invokeBlock(request, (p : P[A]) => child.invokeBlock(p, block))
}
}

trait ActionBuilder[R[_]] extends ActionFunction[Request,R] {
...
}
```

This allows arbitrary processing of the Request and composition of these processes. For example, I define another trait that can choose to provide an immediate result or pass on to another ActionFunction:

```scala
trait ActionRefiner[-R[_],P[_]] extends ActionFunction[R,P] {
protected def refine[A](request : R[A]) : Future[Either[SimpleResult,P[A]]]
final def invokeBlock[A](request : R[A], block : P[A] => Future[SimpleResult]) =
refine(request).flatMap(_.fold(Future.successful _, block))
}
```

I've found this really useful for layering various permission checks or object lookups that can get added to the request.