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]
Related
I am currently Implementing business logic code which is dependent on the custom scala library which has a lot of impure functions and we have a lot of code with is dependent on this library and cannot refactor as it will affect others. So I am trying to write my scala code as pure as possible and need suggestions for few use cases.
I have an LDAP utility library that does the following
Authenticate based on username and password and returns Boolean, However, if there is a Connection exception or user not found it directly throws an exception.
Reading and updating data based on UUID and parameters like first name and last name does pretty much the same thing
My approach for the authentication use case is below
def authenticateToUpdate(userName:String,password:String):Option[Boolean] =
Some(ldapService.authenticate(username,password))
// or using either type to get the message as well
def authenticateToUpdate(userName:String,password:String):Either[String,Boolean]=
(ldapService.authenticate(username,password)) match {
case true => Right(true)
case false => Left("Validation failed, Invalid Password")
case exception: Exception => Left(exception.toString)
}
//##for Some type
authenticateToUpdate(userName,password).fold(InvalidPassword)(updateOrder(orderId,userName))
//##for Either type
// Looking into how to implement
So I want to write my code as functional and close to pure function as possible need help and suggestions on how can I approach such scenario to write functional scala code.
As Tim says, when handling errors in Scala the easiest thing to do is to wrap the exception-throwing code in a Try block. For example:
import scala.util.{Try, Success, Failure}
Try {
connector.makeCall()
} match {
case Success(value) if value => Right("yay")
case Success(value) => Left("☹️")
case Failure(ex) => Left("An exception was thrown")
}
This will return a Right if the connector.makeCall() line returns true or a Left if that line returns false or an exception.
It's a bit of a contrived example but here's one way you'd use this - https://scastie.scala-lang.org/irmbBQ9ISeqgitRubC8q5Q
Actually, the provided piece of code cannot be pure because the result of
authenticateToUpdate depends not only on its arguments (username, password) but also depends on the ldapService service.
Having said that I'd suggest the following definition for authenticateToUpdate:
def authenticateToUpdate(userName:String, password:String)(ldapService: (String, String) => Boolean): Either[String, String] = {
Try(ldapService(userName, password)) match {
case Success(value) if value => Right("OK")
case Success(_) => Right("Failed to authenticate")
caseFailure(ex) => Left(s"Something wrong: ${ex}")
}
}
authenticateToUpdate("user", "password"){ case (user, password) =>
ldapService.authenticate(username,password)
}
In the provided example we just wrap an impure function with a pure one.
In scala concurrent package, there is onComplete method which returns nothing while in akka-http directives, it returns the Directive1.
Is that the only difference? I sometimes got confused on those two methods.
These methods are different in what they aim to accomplish, but they are related in that the akka http onComplete is meant to work with the completion of a Future in order to complete the routing of a request.
The concurrent onComplete is a method on a Future that is meant to perform some sort of side effecting when the Future has completed. There are a lot of other methods on a Future like map, flatMap and filter that will produce another Future as you go through a series of transforms, but onComplete returns nothing, and is sort of a "dead end" in the processing of that Future.
An example of using onComplete while also showing how something like map can be used to change the Future is as follows:
val fut1 = Future{"1"} // A Future[String]
val fut2 = fut1.map(_.toInt) // Now a Future[Int]
fut2.onComplete{
case util.Success(i) => println(s"success: $i")
case util.Failure(ex) => ex.printStackTrace()
}
val badFut1 = Future{"A"}
val badFut2 = badFut.map(_.toInt) //Will be failed
badFut2.onComplete{
case util.Success(i) => println(s"success: $i")
case util.Failure(ex) => ex.printStackTrace()
}
In the first case, we will hit the success case as "1" can be mapped into an Int. In the second example, we will hit the error case as "A" cannot be mapped to an Int. Either way, you can see that something like map can be used to create a new transformed future while onComplete can be used to do something based on the final result of that Future.
In Akka Http, you sometimes need to create Route definitions that need to do something asynchronously. In that case, you need to complete the route when that asynchronous task completed. A Route itself needs to be fully defined in order to compile, so you can't leverage the existing onComplete on a Future because that returns nothing and that would render the definition of that Route as incomplete. Therefore, the guys at Akka defined an onComplete directive that will snap into a routing tree and work with a Future, returning a Directive that will fully define the tree for that Route as oppose to leaving it open ended as the Future.onComplete would. An example:
val myRoute =
get{
val fut = myActor ? "foo"
onComplete(foo){
case util.Success(_) => complete(StatusCodes.OK)
case util.Failure(ex) => complete(StatusCodes.InternalServerError)
}
}
So here, I'm making a request to an Actor using ask (?) and I get a Future back. I still need to produce something that completes the Route I am defining. If I did something like this:
val myRoute =
get{
val fut = myActor ? "foo"
fut.onComplete{
case util.Success(_) => complete(StatusCodes.OK)
case util.Failure(ex) => complete(StatusCodes.InternalServerError)
}
}
It worn't work because the onComplete here is the one from the Future and not the directive, and that returns Unit and my Route won't be full defined and won't compile.
So the onComplete directive is there to allow you to define a Route based on the completion of a Future which you can't do properly with the pre-existing onComplete from Future itself.
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.
I'm writing a Play 2.3.2 application in Scala.
In my application I'm writing a method that call an other controller method like the following:
def addTagToUser = CorsAction.async { request =>
implicit val userRestFormat = UserFormatters.restFormatter
implicit val inputFormat = InputFormatters.restFormatter
implicit val outputWriter = OutputFormatters.restWriter
//update the tag of a user
def updateTagToUserDB(value: JsValue): Future[Boolean] = {
val holder : WSRequestHolder = WS.url("http://localhost:9000/recommendation/ advise")
val complexHolder = holder.withHeaders("Content-Type" -> "application/json")
complexHolder.post(value).map(response => response.status match {//handle the response
case 200 => true
case _ => false
}
)
}
val jsonData = request.body.asJson //get the json data
jsonData match {
case Some(x) => x.validate[Input] match {
case JsSuccess(input, _) => updateTagToUserDB(x).flatMap(status => status match {
case true => Future{Ok}
case _ => Future{InternalServerError("Error on update the users tags")}
})
case e: JsError => Future{BadRequest("json bad formed")}
}
case None => Future{BadRequest("need a json value")}
}
}
But in this code I've the problem that the url is create static, Is possible to get the absolute uri of a Controller method in Play??
How can I make that??
As mentioned in reverse routing section of Play docs, you can achieve this with the following method call:
routes.Application.advise()
Note that routes exists in controllers so if you are in controllers package you can simply access reverse routes with routes.ControllerName.methodName.
From other parts of the code you need to use the fully qualified package, i.e. controllers.reverse.Application.advise().
If controller method takes a parameter you need to pass the desired argument and get the actual route, for example routes.Application.someMethod(10).
Reverse routing is a powerful asset in Play toolbox which frees you from repeating yourself. It's future proof in a sense that if you change your route, the change will be reflected automatically to the whole application.
Alternative
This approach may not be the best approach.
Redirecting to another controller makes sense, but sending a request to another controller which resides just inside the same web app is overkill and unnecessary. It would be more wise if your web app serves responses to outside not to request a response from itself.
You can easily avoid it by putting the common logic somewhere else and use it from both controllers. According to best practices a good controller is a thin one! By better layering life will be much easier.
I'm looking at the example at https://github.com/playframework/Play20/tree/master/samples/scala/websocket-chat
To make a websocket controller, you write something like:
def chat(username: String) = WebSocket.async[JsValue] { request =>
ChatRoom.join(username)
}
Chatroom.join returns a scala.concurrent.Future[(Iteratee[JsValue,_],Enumerator[JsValue])] . But where are the iteratee and the enumerator used within the Play! framework? The WebSocket class (WebSocket.scala) seems to ignore the inputs:
case class WebSocket[A](f: RequestHeader => (Enumerator[A], Iteratee[A, Unit]) => Unit) (implicit val frameFormatter: WebSocket.FrameFormatter[A]) extends Handler {
type FRAMES_TYPE = A
/**
* Returns itself, for better support in the routes file.
*
* #return itself
*/
def apply() = this
}
How does Play! manage the changing state of the iteratee as it consumes input?
It's worth noting that the WebSocket itself is just a dumb container. The magic happens in various classes within play.core.server.netty.
To understand what that magic is, it's instructive to look at the signature of f (the function that a WebSocket contains:
RequestHeader => (Enumerator[A], Iteratee[A, Unit]) => Unit
This is a function that takes a RequestHeader, an Enumerator, and an Iteratee, and does something with them.
So, at some point in the future, the framework will provide our WebSocket with a RequestHeader (which should be self explanatory), an Enumerator[A] (Enumerators are sources, in this case, these are the messages being received from the client), and an Iteratee[A, Unit] (Iteratees are sinks, in this case, this is where we send messages to go back to the client).
In the case of WebSocket.adapter, the WebSocket will connect the Enumerator to the Iteratee via an Enumeratee. In the case of WebSocket.using, the WebSocket will connect the remote Enumerator to a local Iteratee, and connect the remove Iteratee to a local Enumerator.
Rather than defining WebSocket directly, it's likely to be easier to use one of the convenience methods in the WebSocket object. The following code will echo the previous message received:
def mySocket = WebSocket.adapter {implicit req =>
var lastMessage = "No previous message"
Enumeratee.map[String] {msg =>
val response = lastMessage
lastMessage = msg
response
}
}
Note that this code almost certainly has thread safety issues - in Scala, you should try to avoid mutable state whenever possible, or use actors or similar if not.
Or, try WebSocket.using, and look at a pushee Enumerator, in conjunction with a foreach Iteratee, although it's a little fiddler. Perhaps understandably, the pushee enumerator is deprecated in Play 2.1, as it's being superseded by the new channels system.