What's the meaning of: 'request => out => ' in Play Framework - scala

While I was diving in the Play Framework 2 reference documentation, I foun this syntax regarding WebSockets:
def socket = WebSocket.acceptWithActor[String, String] { request => out =>
MyWebSocketActor.props(out)
}
https://www.playframework.com/documentation/2.3.x/ScalaWebSockets
But I'm not able to understand the "meaning" of this syntax 'request => out'. I can infer that from a WebSocket request, I get an ActorRef called out, but I'm asking if anyone can make me see the match with this syntax and the method signature found in their API.
I've used Akka+Scala to develop a small application so I know some scala basic syntax.
Solved
See both Angelo Genovese and bjfletcher answers.

request ⇒ out ⇒ MyWebSocketActor.props(out)
Is a function which takes a RequestHeader and returns a function which takes an ActorRef and returns a Props
in the API you linked this is represented as
f: (RequestHeader) ⇒ (ActorRef) ⇒ Props
it might be easier to visualize this way:
def first(request: RequestHeader) = {
def second (out: ActorRef) = {
MyWebSocketActor.props(out)
}
second _
}

Looking at the definition for acceptWithActor:
def acceptWithActor(f: RequestHeader => HandlerProps)
you see that it takes in a parameter that is a function, which takes in a RequestHeader object and produces a HandlerProps object.
Your goal therefore is to put together a function that takes RequestHeader:
request => { ... produce HandlerProps here ... }
now, you need to return a HandlerProps object, let's have a look at what this is:
type HandlerProps = ActorRef => Props
so, your next goal is to take in an ActorRef object and produce a Props:
request => {
actorRef => {
... produce Props here ...
}
}
now, you need to produce a Props object:
MyWebSocketActor.props(out)
Putting it all together, you have your code there. Play uses the convention of naming the actor reference as out not actorRef.
I hope this helps.
Update (see comments)
You can indeed specify the types:
....acceptWithActor[String, String] { request: RequestHeader => out: ActorRef => ...
which sometimes can read better than without. They're not necessary because they're indeed inferred by the compiler which looks at all this in the same way as I explained above.

Related

Akka HTTP asynchronous directives

I would like to implement an asynchronous session token control in an Akka HTTP-based web server before a series of sensible routes would be processed.
In my idea of implementation, I would have a method that performs the authentication that would look like the following:
def performAuthentication(sessionToken: String): Future[Result]
where Result would be a case class containing the authentication result. In order to perform the authentication, I would like to write a Directive that could be placed before the sensible routes, that would look like the following:
def authenticate: Directive1[SessionToken] = optionalHeaderValueByName("session-token").flatMap {
case Some(sessionToken) if (...) => provide(SessionToken(sessionToken))
case _ => complete(StatusCodes.Unauthorized)
}
with SessionResult a case class wrapping the sessionToken that I would provide to the subsequents routes. In place of the suspension points, I'm forced to await for the Promise result, because if I implement the onComplete ... Success ... Failure pattern, like in the following:
onComplete(this.performAuthentication(sessionToken)) {
case Success(value) if (value.isAuthenticated) => provide(SessionToken(sessionToken))
case Failure(ex) => failWith(ex)
case _ => complete(StatusCodes.Unauthorized)
}
the compiler warns me that provide and complete returns two different types... and it's right.
My question is: is there a way to write an asynchronous Directive that could also provide some value, that could be placed in the normal route definition?
I think you could create a Directive like this
type Token = String
def checkRequest(f: HttpRequest => Future[Token])(implicit ec: ExecutionContext): Directive1[Token] =
Directive { inner => ctx =>
val futureToken = f(ctx.request)
futureToken.flatMap(tkn => inner(Tuple1(tkn))(ctx))
}
You can create this directive by giving it a function that does the authentication. If you want to handle rejections as well Token could be an Either[ErrorAuth, Token]

Akka-HTTP compilation error using custom requireParam() directive

I developed custom generic directive, which will provide param of given type, if it exists, or else reject with my custom exception.
import akka.http.scaladsl.common.NameReceptacle
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.directives.ParameterDirectives.ParamDefAux
import akka.http.scaladsl.server.{Directive1, Route}
class MyCustomException(msg: String) extends Exception(msg)
def requireParam[T](name: NameReceptacle[T])
(implicit pdef: ParamDefAux[NameReceptacle[T], Directive1[T]]): Directive1[T] =
parameter(name).recover { _ =>
throw new MyCustomException(s"${name.name} is missed!")
}
It works ok, if I want to create route, using two parameters, for example:
val negSumParams: Route =
(requireParam("param1".as[Int]) & requireParam("param2".as[Int])) {
(param1, param2) =>
complete((-param1-param2).toString)
}
But if I try to use exactly one parameter, this doesn't compile:
val negParamCompilationFail: Route =
requireParam("param".as[Int]) {
param => // scalac complains about missing type param here
complete((-param).toString)
}
If I use it with pass directive, it works:
val negParamWithPass: Route =
(pass & requireParam("param".as[Int])) { // this pass usage looks hacky
param =>
complete((-param).toString)
}
If I write requireParam() return type explicitly, it works too:
val negParamWithExplicitType: Route =
(requireParam("param".as[Int]): Directive1[Int]) { // DRY violation
param =>
complete((-param).toString)
}
Why do I need these tricks? Why can't it work just with requireParam("param".as[Int])?
Scala version 2.12.1, Akka-HTTP 10.0.10.
This error happens due to the Directive companion object apply method. IT allows to create a Route from a function with parameter (T => Route) => Route:
object Directive {
/**
* Constructs a directive from a function literal.
*/
def apply[T: Tuple](f: (T ⇒ Route) ⇒ Route): Directive[T] =
new Directive[T] { def tapply(inner: T ⇒ Route) = f(inner) }
}
But the T parameter must be a tuple. In your case, the compiler can not build the Route. Your requireParam("param".as[Int]) returns a Directive1[Int] so the apply method doesn´t work because Int is not a Tuple.
To make this work you shoul use tapply method directly:
(requireParam("param1".as[Int])).tapply((param1) =>
complete((-param1._1).toString))
and
val negSumParams2: Route =
(requireParam("param1".as[Int]) & requireParam("param2".as[Int])).tapply {
case (param1, param2) =>
complete((-param1-param2).toString)
}
So it seems that every Directive tries to convert its param to TupleX. For example:
path("order" / IntNumber) returns a Directive[Tuple1[Int]] instead of Directive1[Int]. In your case requireParam("param1".as[Int]) returns Directive1[Int]
Maybe there is a better solution and to avoid tapply
Johannes from Lightbend answered to this question here: https://groups.google.com/forum/#!topic/akka-user/NmQvcrz5sJg Answer is:
You discovered one of the reasons for the magnet pattern. If you use
requireParam("param".as[Int]) { abc => ... } then the { abc => }
block is mistaken as the implicit argument of requireParam. So,
either you are ok with that and require users to use extra parentheses
((requireParam("param".as[Int])) { abc => ... }) or you use the
magnet pattern at this level as well. You can read about the magnet
pattern on the old spray blog
(http://spray.io/blog/2012-12-13-the-magnet-pattern/) or just look
into akka-http sources.
A better way to implement the feature would be just to use the
existing implementation ;) and install a custom rejection handler that
produces whatever output you would like. See
https://doc.akka.io/docs/akka-http/10.0.10/scala/http/routing-dsl/rejections.html#customizing-rejection-handling
for how to do that.

Matching against Value Classes in Akka

I've created the Value Class
final class Feature(val value: Vector[Double]) extends AnyVal
To match against that class in scala:
val d = new Feature(Vector(1.1))
s match {
case a:Feature => println(s"a:feature, $a")
case _ => println("_")
}
This works correctly, but in Akka, with the same class above, in the receive method this is not working:
def receive = LoggingReceive {
case a:Feature =>
log.info("Got Feature: {}", a)
case _ => println("_")
}
When I execute the code, although I am sending a Feature, the case statement that is being executed is case _ => println("_"), but, If I change the code to this:
def receive = LoggingReceive {
case a:Feature =>
log.info("Got Feature: {}", a)
case b:Vector[_] =>
log.info("GOT FEATURE")
case _ => println("_")
}
case b:Vector[_] is executed.
Akka documentation mentions:
The recommended way to instantiate actor props uses reflection at runtime to determine the correct actor construc-
tor to be invoked and due to technical limitations is not supported when said constructor takes arguments that are
value classes. In these cases you should either unpack the arguments or create the props by calling the constructor
manually:
But do not mention nothing about matching against Value classes
Update
Thanks to YuvalItzchakov for the help. The Actor's code is as below:
Actor that receive the message:
def receive = LoggingReceive {
case Feature(a) =>
log.info("Got feature {}", a)
// ....
}
Actor sending the message:
def receive = LoggingReceive {
// ..
case json: JValue =>
log.info("Getting json response, computing features...")
val features = Feature(FeatureExtractor.getFeatures(json))
log.debug(s"Features: $features")
featureListener.get ! features
// ..
}
Due to the nature of how value classes work, both your examples will cause the allocation of Feature. Once due to run-time checking in your pattern matching example, and the other due to the signature of receive which requires Any as the input type.
As the docs for Value Classes specify (emphasis mine):
Allocation Summary
A value class is actually instantiated when:
a value class is treated as another type.
a value class is assigned to an array.
doing runtime type tests, such as pattern matching.
This means that if you're seeing a Vector[_] type, that means your actually passing a concrete vector from some place in the code.

Type mismatch mapping Future[Seq[model]] using Play with Scala

I still struggle sometimes to map Futures using Play with Scala...
I am trying to pass to a view my entire Supply DB table (i.e. all the supplies in the DB).
I have tried two distinct ways but both have failed...
Below are the methods I've tried and the errors I get.
Can someone please help me solve this, and also explain me why both of these have failed?
Thank you in advance!
Note: Calling supplyService.all returns a Future[Seq[Supply]].
First attempt
def index = SecuredAction.async { implicit request =>
supplyService.all map { supplies =>
Future.successful(Ok(views.html.supplies.index(request.identity, SupplyForm.form, supplies)))
}
}
Second attempt
def index = SecuredAction.async { implicit request =>
val supplies = supplyService.all
Future.successful(Ok(views.html.supplies.index(request.identity, SupplyForm.form, supplies)))
}
First variant without Future.succesfull
supplyService.all.map( supplies => Ok(views.html.supplies.index(request.identity, SupplyForm.form, supplies)) )
Since you have can construct function Seq[Supply] => Result you can easily map
Future[Seq[Supply]] to Future[Result] via functor interface.
Future is also a monad , so you can use Seq[Supply] => Future[Result] with flatMap method.
But Future.successfull is monad unit , and as for many monads for Future its true that
mx.flatMap(f andThen unit) = mx.map(f)
so your
ms.flatMap(supplies => Future.successfull(f(supplies)) =
ms.flatMap(f andThen Future.successfull) =
ms.map(f)

Scala Play 2.3 Getting request back in scope

Sorry for my lack of correct terminology, but hopefully the questions is at least understandable :)
I'm implementing a trait which is called out to by a library - so I don't have access over the "middle" of the code.
Controller -> Action (get request in scope) -> Library -> Trait -> my code to save to database
Trying
def insert(newRecord: Token)(implicit request: play.api.mvc.Request[Any]) = database.withSession { implicit db:Session => {
Gives a compile error:
Cannot find any HTTP Request here
Is there anyway to get the request back in scope?
The code:
Specifically, I'm using play2-oauth2-provider, and the relevant pieces of code as I understand are
Get request in scope in Action, this is working correctly
def accessToken = Action.async {
implicit request =>
val header = request.remoteAddress
issueAccessToken(new UserOauth())
The request then gets passed through the library (a few times) - the last point in the library code which request is still in scope is a call -
handler.handleRequest(request, dataHandler)
override def handleRequest[U](request: AuthorizationRequest, dataHandler: DataHandler[U]): GrantHandlerResult = {
.....
issueAccessToken(dataHandler, authInfo)
}
The last line of handleRequest calls to issueAccessToken.
By my understanding, this is where the reference to request is lost, and my question is - "is there any way to get it back." Again, I can't change this code as its in a library.
def issueAccessToken[U](dataHandler: DataHandler[U], authInfo: AuthInfo[U]): GrantHandlerResult = {
...
dataHandler.createAccessToken(authInfo)
}
My code is then
class UserOauth extends DataHandler[Credentials] {
def createAccessToken....
Which eventually calls my data model - where I would like to get something from the request object
Thanks,
Brent
The insert function is requiring a request from the context/caller (that's what the implicit request means there). Not finding a request provided as implicit, the compiler raise the error.
To fix it, you have to declare an implicit for current request (provided by Play Action) in the code calling insert. implicit must be corresponding side by side, between caller and callee, e.g.
def myAction = Action { implicit req => // instead of just Action { req => ... }
insert(myRec)
}
def myAsyncAction = Action async { implicit req =>
Future { insert(myRec)
}
Any implicit parameter is looking for a matching implicit value (def or val) in current implicit scope (from the caller).
Making everying 'explicit' can help to understand insert (and is also sometime better as code), as an implicit parameter is by first a parameter, so following code is also right.
def myAction = Action { req => insert(myRecord)(req) }