Playframework - Request[A] vs RequestHeader

playframework, playframework-2.0, scala

Solution

`RequestHeader` represents the header of the HTTP request. `Request[A]` is a `RequestHeader` plus a parsed request body of `A`. The default body parser in Play detects a few well known body formats (`application/json`, `application/xml`, `text/plain`, `application/x-www-form-urlencoded`, `multipart/form-data`), and parses them automatically into a body of type `AnyContent`, which then lets you access the specific types by calling methods such as `asJson`. If you write an action like:

def myAction = Action { req =>
  ...
}

Then the type of `req` will be `Request[AnyContent]`. On the other hand, if you explicitly specify a body parser, then the type of the request will be the type that that body parser returns, for example:

def myAction = Action(parse.json) { req =>
  ...
}

In that case, `req` will be `Request[JsValue]`. So, the secure social template wants a `Request[AnyContent]`, so firstly, this means you can only use it from actions that use the default body parser. Next, it means that you have to change the signature of your `getLoginPage` to only accept `Request[AnyContent]`, eg:

def getLoginPage(implicit request: Request[AnyContent], form: Form[(String, String)], msg: Option[String]): Html = {
  val req = RequestWithUser(None, request)
  views.html.secure.login(form, msg)(request = req)
}

That should work as is, as long as every action that invokes `getLoginPage` has a request that has been produced by the default body parser.

Problem

I'm unable to understand diffrence between `play.api.mvc.Request[A]` and `play.api.mvc.RequestHeader` and `play.api.mvc.Request[play.api.mvc.AnyContent]`. In compiled class I've got ``` trait Request[+A] extends scala.AnyRef with play.api.mvc.RequestHeader { def $init$() : scala.Unit = { /* compiled code */ } def body : A def map[B](f : scala.Function1[A, B]) : play.api.mvc.Request[B] = { /* compiled code */ } } object Request extends scala.AnyRef { def apply[A](rh : play.api.mvc.RequestHeader, a : A) : scala.AnyRef with play.api.mvc.Request[A] { val remoteAddress : scala.Predef.String def username : scala.None.type val body : A } = { /* compiled code */ } } ``` Request[AnyContent] ---> RequestWithUser[play.api.mvc.AnyContent] ? ``` def getLoginPage[A](implicit request: Request[A], form: Form[(String, String)], msg: Option[String]): Html = { val req = RequestWithUser(None, request) views.html.secure.login(form, msg)(request = req) } ``` This code works in `TemplatePlugin` but it's not working in view: ``` @(loginForm: play.api.data.Form[(String,String)], errorMsg: Option[String] = None)(implicit request: securesocial.core.RequestWithUser[_ <: play.api.mvc.AnyContent]) ``` It's not working because: ``` type mismatch; found : securesocial.core.RequestWithUser[A] required: securesocial.core.RequestWithUser[_ <: play.api.mvc.AnyContent] ``` So I tried to put `AnyContent` as generic type: ``` def getLoginPage[A](implicit request: Request[A], form: Form[(String, String)], msg: Option[String]): Html = { val req = RequestWithUser[play.api.mvc.AnyContent](None, request) views.html.secure.login(form, msg)(request = req) } ``` But next compilation error shown: ``` type mismatch; found : play.api.mvc.Request[A] required: play.api.mvc.Request[play.api.mvc.AnyContent] ``` And play.api.mvc.AnyContent looks like: ``` package play.api.mvc sealed trait AnyContent extends scala.AnyRef { def $init$() : scala.Unit = { /* compiled code */ } def asFormUrlEncoded : scala.Option[scala.Predef.Map[scala.Predef.String, scala.Seq[scala.Predef.String]]] = { /* compiled code */ } def asText : scala.Option[scala.Predef.String] = { /* compiled code */ } def asXml : scala.Option[scala.xml.NodeSeq] = { /* compiled code */ } def asJson : scala.Option[play.api.libs.json.JsValue] = { /* compiled code */ } def asMultipartFormData : scala.Option[play.api.mvc.MultipartFormData[play.api.libs.Files.TemporaryFile]] = { /* compiled code */ } def asRaw : scala.Option[play.api.mvc.RawBuffer] = { /* compiled code */ } } ``` Please help me to solve this problem. Edited - solution so far I found code that compiles and even works well. Nevertheless this is not elegant way because I used `asInstanceOf` and cast class. ``` def getLoginPage[A](implicit request: Request[A], form: Form[(String, String)], msg: Option[String]): Html = { implicit val r = RequestWithUser[play.api.mvc.AnyContent](None, request.asInstanceOf[Request[AnyContent]]) views.html.secure.login(form, msg)(request = r) } ```

Original source