Can http4s do different status codes given a Future? - scala

I'm using http4s, and I have a Try that generates some json data for a response:
case GET -> Root / "something" =>
getSomethingTry() match {
case Success(something) => Ok(something)
case Failure(CustomNotFoundException(reason)) => NotFound(reason)
case Failure(CustomConflictException()) => Conflict()
}
This function correctly returns a Task[Response]
However, I want to replace the Try with a Future. Matching no longer works, because the future may not have been resolved at the time of the match. So, I can map the future:
case GET -> Root / "something" =>
getSomethingFuture().map {
something => Ok(something)
}.recover {
case CustomNotFoundException(reason) => NotFound(reason)
case CustomConflictException() => Conflict()
}
But this returns a Future[Task[Response]] which is not what http4s wants. It doesn't seem appropriate to use Await.result to unbox the Future - I think this could cause thread pool issues - but it does make the code work.
http4s accepts futures as the argument to the task creator:
case GET -> Root / "something" =>
Ok(getSomethingFuture())
But this doesn't let me set different status codes in the event of different errors. A solution could be to do a .recover on a task, but I can't see an obvious way to do that.
How can I call different http4s task wrappers in the event of different Future failure cases? Do I need to use middleware?

Assuming you're using http4s 0.17 and higher, your Task is fs2.Task.
It's easy to convert the Future to Task and then deal with the latter:
case GET -> Root / "something" =>
Task.fromFuture(getSomethingFuture())
.flatMap {
something => Ok(something)
}
.handleWith {
case CustomNotFoundException(reason) => NotFound(reason)
case CustomConflictException() => Conflict()
}
I'd recommend, however, to use Task throughout your program instead of Try or Future

You dont really need to unwrap the future. Play framework provides action.async for returning Future.
You can use it in the following way
Action.async {
getSomethingFuture().map {
something => Ok(something)
}.recover {
case CustomNotFoundException(reason) => NotFound(reason)
case CustomConflictException() => Conflict()
}
}
https://www.playframework.com/documentation/2.6.x/ScalaAsync#returning-futures

Related

Convert a scala.util.Try to a scala.concurrent.Future

I started migrating my Scala 2.11 code base to Scala 2.12. In my application I had a method that looked like this:
Future {
someMethodReturningTry()
} onSuccess {
case Success(result) => processResult()
case Failure(reason) => log.error(s"Couldn't do it: ${reason.getMessage}")
}
Now, if you compile this with Scala 2.12, you'll get:
method onSuccess in trait Future is deprecated (since 2.12.0): use foreach or onComplete instead (keep in mind that they take total rather than partial functions)
So I started exploring how I could solve this in an elegant way.
The someMethodReturningTry() method really should return a Try[], since it involves parsing some text structure and that might fail, so I prefer to keep the return type for that method the same.
The best I could think of is
Future {
someMethodReturningTry()
} flatMap {
case Success(result) => Future.successful(result)
case Failure(reason) => Future.failed(reason)
} onComplete {
case Success(result) => processResult()
case Failure(reason) => log.error(s"Couldn't do it: ${reason.getMessage}")
}
But that feels a bit redundant: creating a Future just to model the fact that something in the future (which already is captured inside a Future) went well.
This approach creates an extra Future which I hope to get rid of, but I can't figure out how. Any suggestions?
It's not clear to me why you don't just...
Future {
someMethodReturningTry() match {
case Success(result) => processResult(result)
case Failure(reason) => log.error(s"Couldn't do it: ${reason.getMessage}")
}
}
You're free to handle, or ignore, the Future failure separately.
You could adjust your pattern matching in the following way:
Future {
someMethodReturningTry()
} onComplete {
case Success(Success(result)) => processResult()
case Success(Failure(reason)) => log.error(s"Couldn't do it: ${reason.getMessage}")
case Failure(reason) =>
log.error(s"The future failed: ${reason.getMessage}")
// or do nothing
}
Note that the onSuccess callback is executed only if the Future succeeds, so your original code didn't do anything if the Future contained an exception. If that is your intent, you can leave the case Failure(reason) => clause above blank (but it's probably more helpful to retain the error logging as shown).

How to test api method for stability and ability to get multiple request simultaneously using scalatest?

I have an api method that calls some service class method and gets a future of Money object (case class):
// getMoneyFromBank() returns a Future[Money]
def getMoney(): Action[JsValue] = Action.async(parse.json) { request =>
request.body.validate[Password] match {
case JsSuccess(password, _) => getMoneyFromBank(password).map {
case money: Money => Ok(money)
} recover {
case ex =>
InternalServerError(ex.getMessage)
}
case JsError(errors) => Future(BadRequest("Errors! " + errors.mkString))
}
}
getMoney method going to be called allot and i want to make sure its very stable and can handle number of calls simultaneously, what would be the best way to test that using scalatest? how do I test this kind of scenario very well?
I work with play 2.6 and scalatest 2.2.6 (and scalatestplus-play 1.5.1)

How can I use a Future inside an Akka HTTP Directive?

I currently have a directive that I'm using to secure resources in an Akka HTTP app, like so:
def authenticate: Directive1[Login] =
optionalHeaderValueByName("Authorization") flatMap {
val accessToken = authz.split(' ').last
case Some(authz) =>
LoggedInUser findByAccessToken accessToken match {
case Some(user) => provide(user)
case None => reject(AuthorizationFailedRejection)
}
case None => reject(AuthorizationFailedRejection)
}
where LoggedInUser.findByAccessToken() makes a blocking query against a database, I would like to switch this for an asynchronous ask to an actor which which can provide the same data, I'm OK with passing in the ActorRef as a parameter to the directive but I cannot work out how to handle the Future that the ask returns.
None of the Directive1 examples that come with Akka HTTP seem to do this (at least I could;t find any) although there are examples of directives returning Route which do.
Is what I want to do even possible? Is a possible approach to create a StandardRoute subclass with a field for the user credentials and return that somehow?
Yes, it is possible. As far as I understand you need something like this:
def authenticate: Directive1[Login] = {
def findByAccessToken(accessToken:String): Future[Option[Login]] = ???
optionalHeaderValueByName("Authorization").flatMap {
case Some(authz) =>
val accessToken = authz.split(' ').last
onSuccess(findByAccessToken(accessToken)).flatMap {
case Some(user) => provide(user)
case None => reject(AuthorizationFailedRejection)
}
case None => reject(AuthorizationFailedRejection)
}
}

In scala how to wrap a PartialFunction?

In scala, Futures have a sort of rescue function that takes a PartialFunction. This code is skipped if the Future resolved with a response but is called if a failure occurs.
I want to simple wrap the partial function in a proxy that always executes code that writes to a stat counter. At first I was thinking I would just create another PartialFunction but soon realized that does not work very well with the isDefined, then apply as I really want this to be called every time.
How do I go about proxying the PartialFunction such that my code is always called when the Future has an exception?
To summarize the comments: You can use the onFailure callback to execute some side-effecting code (logging) when a Future fails.
val future = Future(1 / 0)
future.onFailure {
case _ => println("I have seen the Future, and it doesn't look good.")
}
As #cmbaxter notes, you could also use andThen on the Future, which accepts a PartialFunction[Try[A], B] and returns the original Future. So you could apply the side-effecting function using andThen, and than recover afterwards. You could even chain them multiple times.
Future(1 / 0)
.andThen { case Failure(_) => println("Future failed.") }
.recover { case e: ArithmeticException => 0 }
.andThen { case Failure(_) => println("Tried to recover, and still failed.") }
Or a helper that always includes it:
object FutureLogger {
def apply[A](a: => A): Future[A] = Future(a).andThen {
case Failure(_) => println("FAILURE")
}
}

Why does IDEA give warning when returning a Future of None?

For the following snippet IDEA gives a warning, that future {None} would be redundant:
queryString match {
case Some(query) => ... // Do async call
case None => future { None }
}
Is there a better possibility to do it?
You can create an already set future without spawning a closure, using Future.successful[T](result: T), so maybe Future.successful(None) is what you want.
Since futures already distinguish between success and failure independent of their type parameter, however, you could signalise a failure also through Future.failed(new Exception("No query string")), given that your async call can also omit the wrapping in Some.
I don't know if IDEA's warning is helpful in this case.
You could potentially silence it by pushing the matching down into the future:
future {
queryString match {
case Some(query) => Some(computeResult(query))
case None => None
}
}
(or more briefly: future { queryString.map(computeResult(_)) })
I think i solved it by myself: I don't need an Option encapsulated in my Future, because the Future itself can also fail and therefore an failure is kind of equal to a None.
Now i only return a Future and:
queryString match {
case Some(query) =>
//async Call which returns a Future without Option
case None => throw new Exception("Error")
}