Playframework 2.2 Action Building and Action Composition

Play 2.2 Building and Composing Actions

New Results in 2.2

One of Play 2.2’s biggest changes is the complete overhaul of the Action and Results architecture. While it did work pretty well in earlier versions, there also used to be a great variety of Results to choose from:

  • Result
  • PlainResult
  • SimpleResult
  • AsyncResult
  • ChunkedResult

Play 2.2 reduces all this to SimpleResult (to be renamed to Result in 2.3). The previous result types have been deprecated and will be removed in Play 2.31.

This leads to the following mapping:

Play 2.0/2.1 Play 2.2
Result, SimpleResult, PlainResult SimpleResult
AsyncResult Future[SimpleResult]
ChunkedResult SimpleResut (via Status.chunked(Enumerator))

Actions

Overview

To produce a SimpleResult or Future[SimpleResult] easily, Actions now work differently than before.

The official documentation is sparse as always, so I want to give an overview over the changed principles of Actions and Action composition. This article doesn’t show many code examples because I created a new PlayBasics sub-project that walks you through the presented concepts.

EssentialAction

On the top of the Action hierarchy sits EssentialAction2, already introduced with Play 2.1 and until now mostly used when dealing with EssentialFilters or streaming data directly from the request.

An EssentialAction is closer at Play’s implementation details than an Action. It is defined like this:

trait EssentialAction extends (RequestHeader => Iteratee[Array[Byte], SimpleResult])

So an EssentialAction extends a function from RequestHeader to an Iteratee. If that confuses you, just rewrite it as a class:

class EssentialAction extends Function1[-RequestHeader,+Iteratee[Array[Byte], SimpleResult]] {
  def apply(rh: RequestHeader): Iteratee[Array[Byte], SimpleResult]
}

When executed, an EssentialAction takes a RequestHeader, and from that RequestHeader it returns an Iteratee that consumes a byte array and eventually produces a SimpleResult3.

The byte array represents the raw, unparsed body. As we can see, an EssentialAction is the generic interface that takes an incoming RequestHeader and provides the means (the Iteratee) that can then parse the body and eventually produce a SimpleResult (expressed as a Future[SimpleResult]). The SimpleResult will be part of the HTTP response header which is handled completely by Play.

EssentialActions should be used to create composable actions that operate at the RequestHeader level. In terms of composability, EssentialActions are far superior to Actions and ActionBuilders because they are just functions. This means we can use curried functions and build new functions on top of previous ones4.

EssentialActionA(block: Int => EssentialAction) = EssentialAction { rh =>
  block(42)(rh)
}

EssentialActionB(action: EssentialAction) = EssentialActionA { answer => // Compose it directly
  EssentialAction { rh =>
    if (answer == 42) {
      action(rh)
    } else {
      Done(BadRequest) // Iteratee is leaking in our Action
    }
  }
}

A disadvantage is that in your controller you always have to wrap the EssentialAction around a normal action (or you won’t have access to the request body), and that EssentialActions are sometimes a little harder to handle due to their "raw" nature.

Please check out the example code for EssentialActions in controllers/EssentialActions.scala.

BodyParser

So how does an EssentialAction parse the request body? This is where a BodyParser comes into play. A BodyParser looks similar to the EssentialAction itself:

trait BodyParser[+A] extends (RequestHeader => Iteratee[Array[Byte], Either[SimpleResult, A]])

This tells us that a BodyParser also takes the RequestHeader and builds an Iteratee that parses the request body, but returns either a SimpleResult or the type A it was constructed with.

This return type branching is useful because you might imagine that the body parser would reject the body’s content – for example, a JSON body parser only understands JSON content, so it can return a 400 Bad Request directly when it encounters the wrong content. Otherwise it will parse the body and eventually produce A, the BodyParser’s type (in the case of the JSON parser, A would resolve to JsValue).

Play’s built-in body parsers are accessible via play.api.mvc.BodyParsers.parse. There’s a default BodyParser that is used when you don’t specify one – parse.anyContent. This body parser infers the body’s type from the Content-Type header and tries to parse it accordingly. Finally, you can also specify to ignore the body by using parse.empty.

Action

EssentialAction is pretty much only an interface. In your controllers you will either wrap the EssentialAction around an Action, or use an Action directly without any EssentialAction5. Action[A] inherits from EssentialAction but provides a Request[A] instead of a RequestHeader, where A is the type given by the BodyParser.

Due to the eventual nature of the Iteratee, an Action expects a Future[SimpleResult] rather than a SimpleResult, so there are still some inconveniences when using the new API. Action is a trait that you inherit from, requiring you to implement apply and parser.

class MyAction[A] extends Action[A] {
  def apply(request: Request[A]): Future[SimpleResult] =
    if (request...) Future.successful(Ok)
    else Future.successful(BadRequest)

  def parser: BodyParser[A] // set directly or pass as constructor argument
}

Please check out the example code for Actions in controllers/Actions.scala.

ActionBuilder

An ActionBuilder makes building Actions easier. An ActionBuilder provides shortcuts for handling Result instead of Future[Result], for wrapping requests, and to compose actions.

ActionBuilder’s workhorse is async which actually builds the Action. async takes a body parser and a block of WrappedRequest[A] => Future[SimpleResult] to accomplish this.

The interesting thing is that when you define an ActionBuilder, you are also building Actions on the fly. You can call async directly to statically define an Action, however when you don’t do this, you gain the ability to handle Result and Future[SimpleResult] without any headache.

object MyAction extends ActionBuilder[Request] {
  def invokeBlock[A](request: Request[A], block: Request[A] => Future[SimpleResult]) = ...
}
// Calls ActionBuilder#apply
MyAction { request =>
  Ok
}
// Calls ActionBuilder#async
MyAction.async { request =>
  Future {
    Ok
  }
}

The same goes for Action itself, that means when you are calling Action { ... } you are not calling Action#apply(), but ActionBuilder#apply().

Please check out the example code for ActionBuilders in controllers/ActionBuilders.scala.

Composing Actions and ActionBuilders

One of the key aspects of Actions (and Play, for that matter) is composability. We don’t want to write functionality again and again or call helper methods from all over the place. Actions offer a clear level of abstraction of controller logic, and combining them on the spot to declare certain behaviors is very powerful.

Actions do not support wrapping other Actions by default, this is something you have to do yourself. A typical pattern for this looks like the following:

case class MyAction[A](action: Action[A]) extends Action[A] {
  def apply(request: Request[A]): Future[SimpleResult] = {
    ...
    val result = action(request)
    ...
    result
  }
  def parser = action.parser
}

This creates a new Action that takes as constructor parameter another action. Only this allows you to write:

MyAction {
  Action {
    Ok
  }
}

Since we don’t to specify the parser multiple times, we use the wrapped action’s parser. But this also makes it impossible to pass a parameter to the wrapped Action.

This is solved by ActionBuilders. As you may have noticed, ActionBuilder is typed to R[_]. What does that mean? It means we have to provide some type R that in turn takes some undefined type parameter. In other words, ActionBuilder expects a parsed Request[A], but it doesn’t care what A is as long as it’s consistently the same A6, and will just pass it down to the Action that is being built. This makes possible what’s so hard with Actions, that is to pass on your own data to the next Action. You would usually do this using a WrappedRequest.

case class AuthenticatedRequest[A](user: User, request: Request[A]) extends WrappedRequest(request)

object Authenticated extends ActionBuilder[AuthenticatedRequest] {
  def invokeBlock[A](request: Request[A], block: AuthenticatedRequest[A] => Future[SimpleResult]) = {
    // Check authentication
    val user = ...
    block(AuthenticatedRequest(user, request))
  }
}

Authenticated { request =>
  Ok(Json.obj("userName" -> request.user.fullName))
}

Check out the example code in controllers/ActionComposition.scala.

Summary

An EssentialAction defines behavior before the request body is being considered, so (composable) functions that can be computed from the header should be put in an EssentialAction for Action-specific behavior or in an EssentialFilter for global behavior.

An Action abstracts away the Iteratee, providing a parsed request body in Request[A] and expects a Future[SimpleResult].

An ActionBuilder make building Actions easier, and allows you to switch between SimpleResult and Future[SimpleResult] easily. Try to use this most of the time.

A BodyParser parses the request body, from byte array either to a SimpleResult or to the expected body type A which in turn will become Action’s Request[A].

Please add a comment below or open a pull request if you think there is anything missing.


  1. The helper subclass Status will still exist to easily build Results such as Ok.

  2. EssentialAction and SimpleResult – naming things, right?

  3. If you’re not familiar with Iteratees, in short it is a wrapped function that consumes a stream of input values and eventually produces output values. The input values are feed iteratively, and likewise the Iteratee can produce output from the fed input immediately (so it streams the data). An Iteratee is a finite state machine that knows the three states Continue, Done, and Error. If you call the Iteratee’s run method, all of its input will be consumed, and it returns the result in a Future.

  4. This is also how Actions worked previously, and I’m not so glad they changed this.

  5. Play handles both EssentialActions (return type Iteratee) and Actions (return type SimpleResult or Future[SimpleResut]) transparently

  6. A good explanation of this can be found here: http://blogs.atlassian.com/2013/09/scala-types-of-a-higher-kind/

Posted in Programming
13 comments on “Playframework 2.2 Action Building and Action Composition
  1. keth says:

    Thank you for this detailed explanation. :) Glad I stumbled upon your posting on the mailing list.

  2. Sebas says:

    Nice explanation (but you forgot to explain it for the Java developers)

  3. Mike says:

    Great post. I will be studying both it and your PlayBasics code carefully since migrating my app from 2.1 is proving to be something of a nightmare. I seem to have relied heavily on the transparent unwrapping AsyncResults and now I have a lot of refactoring to do.

    • marius says:

      I feel your pain. Luckily in my case it has lead to sometimes easier to read code. Except when you have to wrap five branches with Future.successful.

  4. 囚千任 says:

    cool, this clear my mind

  5. pk11 says:

    nice writeup.

    Just one comment: ChunkedResult became SimpleResult in play 2.2, not Status.chunked. Status.chunked is the function that will return a SimpleResult

  6. Chris says:

    Thanks for this post. It helped me prevent doing a WS.url call to localhost. I think the example scala file doesn’t compile. It’s missing this line:

    case class Department(name: String)

  7. tiGer says:

    Nice article!
    Thanks!

  8. Martin Burger says:

    Any idea How to wrap Actions (in any order) when using Play’s ActionBuilder?? Basically, I would like to compose Actions defined using Play’s ActionBuilder in arbitrary order. At the same time, I would like to pass data into each action (like tokens and extracted user information).

  9. shashi says:

    Would you please update the document or extend the series to Play 2.3?

  10. Venkatesh says:

    excellent guide. This should go in to the main documentation

Leave a Reply

Your email address will not be published. Required fields are marked *

*


7 − seven =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>