2

Why does the following Play syntax work

def handleForm = Action(parse.tolerantFormUrlEncoded) { implicit request =>
  val username = request.body.get("username").map(_.head).getOrElse("");
  Ok("Username was " + username)
}

Without specifying the type of request, how would the compiler know how to resolve the implicit?

2 Answers 2

2

An Action in Play can be seen as a function: Request[A] => Result. Internally an Action is defined like trait Action[A] extends EssentialAction

The type A is actually the one which allows you to put anything in there. As you can see from the code, the Request is defined like this: trait Request[+A] extends RequestHeader. Interesting here is also the plus sign (+). It is the so-called covariant annotation. This covariant type parameter is one which is allowed to vary down as the class is subtyped. It means that if you have something like

trait List[+A]

then List[Int] is a subtype of List[AnyVal] because Int is a subtype of AnyVal. This means that you may provide an instance of List[Int] when a value of type List[AnyVal] is expected.

All this allows you to have a super generic request which serves as a base for your action and therefore no compile time troubles should be expected.


And something as for why is this all necessary from a more user-related point of view:

From the Play Scala documentation:

It is often useful to mark the request parameter as implicit so it can be implicitly used by other APIs that need it:

Action { implicit request =>
  Ok("Got request [" + request + "]")
}
Sign up to request clarification or add additional context in comments.

Comments

2

It doesn't actually resolve the implicit, you mark the parameter as implicit, for further method calls inside the request handler. Whenever you call a method which accepts an implicit Request parameter, the request argument from the request handler will be automatically passed to it. If you wouldn't mark the request argument as implicit, you'd have to explicitly pass the request argument for each method call who needs an implicit request parameter.

update: upon your comment I updated your code with type parameters to clarify. So even when you use different BodyParsers, your request parameter is still going to be of Request type, so there is no need to convert it, it's just going to be parametrized differently based on your body parser. request.body is going to have the same type as the type parameter, Map[String, Seq[String]] in this example. If you use a JSON body parser then your request parameter would be a Request[JsValue], and the request.body is a JsValue.

def handleForm: Action[Map[String, Seq[String]]] = Action(parse.tolerantFormUrlEncoded)({ 
  implicit request: Request[Map[String, Seq[String]]] =>
    val username = request.body.get("username").map(_.head).getOrElse("")
    Ok("Username was " + username)
})

tl;dr You can just do Action(...) { request => ... } if you don't need an implicit Request for further method calls inside the request handler

4 Comments

How does the compiler know the method accepts an implicit Request parameter? My method handleForm simply accepts an implicit parameter called request for which the naming is arbitrary?
your method accepts an explicit Request parameter, which is going to be implicit inside the method's body for the subsequent function calls, like this one: playframework.com/documentation/2.4.x/…
oh I see, then there must be a method somewhere that transform parse.tolerantFormUrlEncoded to request type right? Since parse.tolerantFormUrlEncoded.body returns an error.
@Kevin I added some explanation, hope that makes clear. It's normal that parse.tolerantFormUrlEncoded.body returns an error, because parse.tolerantFormUrlEncoded is a body parser, not a Request. But request.body is going to be the right type, corresponding to your type parser

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.