Because I have a request body, I need to get it as future and send the response after an action. But, I need to check if the body is valid and if is not, I want to return a BadRequest status.
I know is too much code, so please look inside the requestFuture
, in recover function is the problem.
(pathPrefix("api" / "search") & post & extractRequest) { request =>
val tokenResult = request.headers.find(x => x.name.toLowerCase == "token")
tokenResult match {
case None => throw new IllegalArgumentException(ServerMessages.TOKEN_NOT_FOUND)
case Some(token) => token.value match {
case this.apiToken => {
val entity = request.entity
val strictEntityFuture = entity.toStrict(2 seconds)
val requestFuture = strictEntityFuture
.map(_.data.utf8String.parseJson
.convertTo[SearchFilters])
requestFuture map { filters =>
// here - I return an Route with data from controller
complete(controller.searchData(filters)
.map(_.toJson.prettyPrint)
.map(toHttpEntity)))
} recover (e => {
// HERE IS THE PROBLEM
// I need to return an Route, but here will be a Future[Route]
complete(400 -> ServerMessages.INVALID_REQUEST_BODY)
}
}
case _ => throw new IllegalArgumentException(ServerMessages.INVALID_TOKEN)
}
}
I need to unpack the response from the future, or to use another way to throw the error.
found a solution using onComplete
directive, but I need to know if my json is successfully converted or not, to can throw a custom error.
onComplete(requestFuture) {
case Success(filters) => searchKpi(filters) ~
pathEndOrSingleSlash {
complete(403 -> ServerMessages.INVALID_METHOD_ARGUMENTS)
}
case Failure(ex) => failWith(ex) // returns 500 Internal Server Error
}
thanks
You can use an ExceptionHandler.
Define your exception handler like in the doc and add a case from your exception(which should be the same that is thrown by failWith
) to the HTTP Status you need to return (You mention BadRequest
)
case class MyBadException() extends RuntimeException
implicit def myExceptionHandler: ExceptionHandler =
ExceptionHandler {
case MyBadException() => complete(HttpResponse(BadRequest)) // You decide the HTTP status to return
case _ => complete(HttpResponse(InternalServerError, entity = "Bad numbers, bad result!!!"))
}
val route = path("test") {
onComplete(getSomething()) {
case Success(v) => complete("Ok")
case Failure(err) => failWith(MyBadException())
}
}
Note that you have 2 ways to attach the exception handler
From the doc:
Bring it into implicit scope at the top-level. Supply it as argument to the handleExceptions directive.