Ответ 404 - программирование
Подтвердить что ты не робот

Ответ 404

У меня есть служба, которая возвращает параметр [ProductDoc] в будущем (в качестве запроса akka)

Как мне ответить в маршрутизации распыления, чтобы действительный продукт воспроизводился с продуктом, но неизвестный, но хорошо сформированный, возвращает 404?

Я хочу, чтобы код заполнил пробел здесь:

get {
    path("products" / PathElement) { productID:String =>
      val productFuture = (productService ? ProductService.Get(productID)).mapTo[Option[ProductDoc]]

      // THE CODE THAT GOES HERE SO THAT
      // IF PRODUCT.ISDEFINED RETURN PRODUCT ELSE REJECT

    }
}

Единственный способ, которым я могу работать, - это эта мерзость:

get {
    path(PathElement) { productID:String =>
      val productFuture = (productService ? ProductService.Get(productID)).mapTo[Option[ProductDoc]]
      provide(productFuture).unwrapFuture.hflatMap {
        case x => provide(x)
      } { hResponse:shapeless.::[Option[ProductDoc], HNil] =>
        hResponse.head match {
          case Some(product) => complete(product)
          case None => reject
        }
      }
    }
  }

Это не может быть правильным способом достичь этого, верно? Это похоже на довольно простой шаблон, который, должно быть, кто-то уже решил!

4b9b3361

Ответ 1

Спрей уже поддерживает ваш прецедент: значение параметра None по умолчанию привязано к EmptyEntity. Вероятно, это то, что вы видели, прежде чем вы внесли какие-либо изменения: 200 с пустым документом. Там есть директива, которая преобразует пустой документ в 404, rejectEmptyResponse, который вы обертываете вокруг частей вашего маршрута, где вы хотите этого поведения.

Ваш маршрут будет выглядеть так:

  rejectEmptyResponse {
    path("products" / PathElement) { productID:String =>
      val productFuture = // same as before
      complete(productFuture)
    }
  }

Конечно, вы можете поместить rejectEmptyResponse внутри пути в зависимости от того, хотите ли вы обернуть с ним больше частей маршрута.

Дополнительная информация:

Ответ 2

У меня такая же проблема несколько дней назад, и я пришел к этому решению:

Я добавил этот метод своему актеру

def failIfEmpty[T](item: Future[Option[T]], id: String) = {
    (item map {
      case Some(t) => t
      case None => throw NotFoundException(Message(s"id '$id' could not be        found",`ERROR`))
    }) pipeTo sender
}

Конечно, вы можете выбрать Exception, которое вам нравится, NotFoundException является одним из моих собственных...

Позвоните по этому результату, чтобы ответить на запрос от вашего актера (это пример использования ReactiveMongo, замените collection.find(query).headOption на Future[Option]):

failIfEmpty(collection.find(query).headOption, id)

Затем добавьте ExceptionHandler к вашей службе (где ваш маршрут определен), как показано ниже:

implicit val klaraExceptionHandler = ExceptionHandler.fromPF {
    case InternalServerErrorException(messages) => complete(InternalServerError, messages)
    case NotFoundException(message) => complete(NotFound, message)
    case ValidationException(messages) => complete(PreconditionFailed, messages)
    [and so on]
}

Таким образом, вы можете обрабатывать несколько разных ошибок, которые возникают в вашем будущем - результаты.