Kazuya Tomita
Kazuya Tomita

Reputation: 697

What does using "implicit request" mean in Play?

My Scala level is a beginner and I saw an action method clearly demonstrating a declaration implicit request=>. And my question is under what types of situation should we declare clearly? I also have seen methods which don't declare implicit request=> or request=>. Could anyone explain the advantage?

Upvotes: 2

Views: 3638

Answers (3)

pvlbzn
pvlbzn

Reputation: 136

Another example with similar API to play's implicit req => ...

case class ClassName(name: String)

def log(msg: String)(implicit className: ClassName) =
  System.out.println(s"message=`$msg` className=`${className.name}`")

val cls = Option(ClassName("ImplicitClass"))

cls.foreach { implicit name =>
  log("explicit message")
}

Produces

message=`explicit message` className=`ImplicitClass`

Upvotes: 1

archz
archz

Reputation: 1072

I will not cover the meaning of implicit in scala itself as it has already been answered on stackoverflow here. The play documentation also explains the use of request => here but does not give examples of a useful implicit request.

TL; DR : when in doubt, use implicit request as it may be needed by some components.

Action without request

If the request does not change the result your block of code will return, it can be omitted and you can write.

def myAction = Action { Ok("Hello World") }

With Request

If on the other hand you need to use the content of the request (header or body), then you have to add a request parameter. A common example of this is parsing the body of the request :

Action(parse.json) { request => // it works without implicit
  request.body.validate[MyClass].fold(/* do something */)
}

With implicit request

The play documentation encourages us to mark the request parameter as implicit because even if you do not use the request directly, one component you use may need it as an implicit. If you ever get a missing implicit error in one of your action, it probably boils down to the fact that you forgot to make your request implicit.

I think a good example you might encounter in play is the internationalization API. To sum up, it allows to automatically inject localized messages in your templates depending on the Accept-Language header in the request. All you have to do is add the I18nSupport trait to your controller and inject a messagesApi: MessagesApi parameter (and obviously define your internationalized messages). Then, in your twirl template, you can use the localized messages. For instance :

Template :

@()(implicit messages: Messages)
@* 
 message will be in english, spanish, klingon... depending on the supported 
 languages and request Accept-Language header
*@
@messages("say-hello") 

Controller :

class MyController @Inject() (val messageApi: MessageApi) extends Controller with I18nSupport {
  def myAction = Action {implicit request => 
    // We do not have to bother about how messages are injected
    // The I18nSupport trait does the work for us
    Ok(html.myTemplate()) 
  }
 }

To be able to do this, the I18nSupport trait contains a def :

implicit def request2Messages(implicit request: RequestHeader): Messages = /* ... */

It allows to get an instance of Messages automatically (the compiler will implicitly call request2Messages(yourRequest) when needed but you need to have an implicit request (or request header) in scope.

Another example I have seen is automatically getting a user instance in the scope of the action when using some security frameworks in play.

Side note

A annoying gotcha with this kind of implicit chain is that if you forget to make your request implicit, the compiler will probably complain about a missing implicit Messages in scope while the real problem is a missing implicit request.

Upvotes: 8

Jacob Wang
Jacob Wang

Reputation: 4794

implicit in Scala has many use cases - one of them being passing parameters implicitly to functions that define implicit parameters.

For example:

def withImplicitParameter(greeting: String)(implicit name: String): Unit = {
  println(greeting + " " + name)
}

// Using implicits
implicit val name = "Bob"
withImplicitParameter("Hello") // "Bob" is passed in implicitly for name parameter. Prints "Hello Bob"
withImplicitParameter("Bye")("Joe") // "Joe" is passed in explicitly for name parameter. Prints "Bye Joe"

Therefore unless one of the functions you're calling has an implicit parameter of the type Request you don't need { implicit request => ... }

More info can be found in Scala's official documentation on implicit parameters

Upvotes: 2

Related Questions