Я работаю над API для управления библиотекой в Scala, используя Slick и Akka-Http. Я определил конечную точку, которая принимает id: Int и передает ее функции, которая принимает целое число и возвращает Future[Option[Book]]
:
def getBook(id: Int) = {
db.run(bookByIdQuery(id).take(1).result.headOption).
map(result => result.map(Book.tupled))}
Я хотел бы использовать его, чтобы дать ответ, что-то вроде:
lazy val route = pathPrefix("books") {path(IntNumber) { id => complete(getBook(id)}}
Вышеприведенное для простоты предполагает, что Book
можно сортировать, и функция всегда дает правильный ответ.
Моя главная проблема в том, как получить значение из этого будущего? До сих пор я пробовал:
Await.result
в теле функции. Это работает, но мне сказали, что это плохая практика — насколько я понимаю, мы не вводим параллельное выполнение только для того, чтобы заморозить один поток и заставить его ждать другого.onComplete
или foreach
, но их тип возвращаемого значения — Unit, поэтому что-то вроде:lazy val route = pathPrefix("books") {path(IntNumber) { id => getBook(id).foreach{i => complete(i)} }}
не работает, потому что для маршрута требуется возвращаемый тип Route, а не Unit.
Итак, какой самый эффективный способ превратить Future[Book]
в Book
и передать его в ответ?
Попробуйте использовать akka.http.scaladsl.server.directives.FutureDirectives
у него есть методы работы с Future
результатами.
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}")
}
}
}
Здесь вы можете найти больше примеров: https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/future-directives/onComplete.html
Спасибо, теперь все работает отлично. Если у меня может быть другой вопрос - если я запрашиваю несуществующую книгу (идентификатор не находится в базе данных), она никогда не достигает части сбоя - я просто получаю общее "Произошла внутренняя ошибка сервера". - Вы знаете, что может быть причиной?
Я могу предположить, что вы столкнулись с необработанным исключением, которое было перехвачено обработчиком ошибок akka http по умолчанию. Но я не уверен в источнике ошибки, которая выбрасывает не внутрь вашего будущего. Можно попробовать отследить с помощью другой директивы handleExceptions(yourCustomErrorHandler)
- doc.akka.io/docs/akka-http/current/routing-dsl/directives/…
Вы можете
map
значения вFuture
лайкнутьcomplete(getBook(id).map(???))
.