Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playframework - Request[A] vs RequestHeader

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)
  }
like image 974
r.piesnikowski Avatar asked Dec 02 '13 22:12

r.piesnikowski


1 Answers

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.

like image 153
James Roper Avatar answered Oct 02 '22 01:10

James Roper