I'm not sure if this is the best way to do this, but I managed to find a solution that seems to work very well.
The key must have AccountWrappedRequest request, converting it to AccountWrappedRequest inside invokeBlock , before passing it to the next request. If another action in the chain expects values ββfrom an earlier action in the chain, you can likewise match the request, converting it to the type needed to access the request parameters.
Updating the example from the original question:
case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request) case class Account[A](action: Action[A]) extends Action[A] { lazy val parser = action.parser def apply(request: Request[A]): Future[SimpleResult] = { AccountService.getBySubdomain(request.host).map { account => action(AccountWrappedRequest(account, request)) } getOrElse { Future.successful(NotFound(views.html.account_not_found())) } } } object AccountAction extends ActionBuilder[AccountWrappedRequest] { def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = { request match { case req: AccountRequest[A] => block(req) case _ => Future.successful(BadRequest("400 Invalid Request")) } } override def composeAction[A](action: Action[A]) = Account(action) }
Then, inside the apply() method of another action (the "Validation" action in my case), you can also do:
def apply(request: Request[A]): Future[SimpleResult] = { request match { case req: AccountRequest[A] => { // Do something that requires req.account val user = User(1, "New User") action(AuthenticatedWrappedRequest(req.account, user, request)) } case _ => Future.successful(BadRequest("400 Invalid Request")) } }
And you can bind actions together in ActionBuilder
override def composeAction[A](action: Action[A]) = Account(Authenticated(action))
If AuthenticatedWrappedRequest then passed to the controller, you will have access to request.account , request.user and all the usual request parameters.
As you can see, there are several cases where the answer is unknown, which generates BadRequest . In fact, they should never be called, as far as I can tell, but they just crack there.
I would like to get some feedback on this solution, since I'm still pretty new to Scala, and I'm not sure there might be a better way to do this with the same result, but I hope that someone else use this too.