Вариант результата в akka-http

У меня возникла проблема при попытке вернуть результат Option из aka-http.

По сути, это может быть 404.

pathPrefix("contacts" / Segment) { id =>
    get {
      contactService.getById(id).map {
        case Some(c: ContactDto) => complete(OK -> toResource(c))
        case None => complete(HttpResponse(NotFound))
      }
    }
  }

Что дает мне и ошибку:

[error]  found   : scala.concurrent.Future[akka.http.scaladsl.server.StandardRoute]
[error]  required: akka.http.scaladsl.server.Route
[error]     (which expands to)  akka.http.scaladsl.server.RequestContext => scala.concurrent.Future[akka.http.scaladsl.server.RouteResult]
[error]       contactService.getById(id).map {

Любая помощь будет принята с благодарностью.

2 ответа

Проблема, которую вы видите здесь, связана с тем, что вы используете Future а не из-за Option, Я собираюсь предположить, что вызов contactService.getById(id) возвращает Future, В результате любой маршрут в вашем дереве маршрутизации должен быть Route (Короче для RequestContext => Future[RouteResult]) и ваш Future само по себе не Route, тогда вам нужно внести небольшое изменение, чтобы справиться с этой ситуацией. Вы должны быть в состоянии использовать onComplete директива в сочетании с вашим Future следующее:

pathPrefix("contacts" / Segment) { id =>
  get {
    val fut = contactService.getById(id)
    onComplete(fut){
      case util.Success(Some(c: ContactDto)) => 
        complete(OK -> toResource(c))
      case util.Success(None) =>
        complete(HttpResponse(NotFound))
      case util.Failure(ex) =>
        complete(HttpResponse(InternalServerError))
    }
  }
}

Этот код теперь обрабатывает 3 возможных результата из Future (успех с SomeУдачи с собой None и провал), производя Route для каждого из этих случаев. Это должно исправить вашу проблему.

Ответ @cmbaxter верный, но если вы довольны стандартными кодами состояния для трех вышеупомянутых случаев (Ok, NotFound, InternalServerError), то вы можете упростить код, чтобы он просто выполнялся напрямую с возвращаемой функцией Future[Option[T]],

pathPrefix("contacts" / Segment) { id =>
  get {
    complete(contactService.getById(id).map(toResource))
  }
}

Это предполагает, что toResource возвращает тип, где ToEntityMarshaller существует для типа, возвращаемого этой функцией. Акка предоставляет оборудование для Future а также Option так что вам просто нужно поставить T часть. Например, если вы возвращали JSON и использовали Spray-JSON, вы можете определить JsonWriter[T] и последствия в akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport сделает все остальное Смотрите спрей-json-support.

map(toResource) может на самом деле не требуется, но я предполагаю, что делает дополнительное преобразование ContactDto к другому типу - если он просто конвертирует его в json или аналогичный, вы можете удалить его и использовать встроенную поддержку сортировки, как описано выше.

Другие вопросы по тегам