i'm working on an api for library management in Scala, using Slick and Akka-Http. I defined an endpoint, that takes id: Int, and passes it to the function, that takes integer and returns Future[Option[Book]]
:
def getBook(id: Int) = {
db.run(bookByIdQuery(id).take(1).result.headOption).
map(result => result.map(Book.tupled))}
I'd like to use it to give a response, something like:
lazy val route = pathPrefix("books") {path(IntNumber) { id => complete(getBook(id)}}
The above, for the sake of simplicity, assumes that Book
is marshallable, and the function always gives correct answer.
My main problem, is how to get the value from this future? So far i tried:
Await.result
in the function body. It works, but i was told it is a bad practice - as i understand, we don't introduce parallel execution just to freeze one thread and make it wait for the other.onComplete
or foreach
- but their return type is Unit, so, something like:lazy val route = pathPrefix("books") {path(IntNumber) { id => getBook(id).foreach{i => complete(i)} }}
doesn't work, because route requires return type of Route, not Unit.
So, what's the most effective way of turning Future[Book]
into Book
and passing it in response?
Try to use akka.http.scaladsl.server.directives.FutureDirectives
it has methods to work with Future
results.
import akka.http.scaladsl.server.directives.FutureDirectives._
val route =
pathPrefix("books") {
path(IntNumber) { id =>
onComplete(getBook(id)) {
case Success(book) => complete(book)
case Failure(ex) => complete(InternalServerError, s"An error occurred: ${ex.getMessage}")
}
}
}
Here you can find more examples: https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/future-directives/onComplete.html