Exception Handling
Exceptions thrown during route execution bubble up through the route structure to the next enclosing
handleExceptions directive, The runRoute Wrapper or the onFailure
callback of a
future created by detach
.
Similarly to the way that Rejections are handled the handleExceptions directive delegates the actual job of converting a list of rejections to its argument, an ExceptionHandler, which is defined like this:
trait ExceptionHandler extends PartialFunction[Throwable, Route]
The runRoute Wrapper defined in The HttpService does the same but gets its ExceptionHandler
instance
implicitly.
Since an ExceptionHandler
is a partial function it can choose, which exceptions it would like to handle and
which not. Unhandled exceptions will simply continue to bubble up in the route structure. The top-most
ExceptionHandler
applied by The runRoute Wrapper will handle all exceptions that reach it.
So, if you’d like to customize the way certain exceptions are handled simply bring a custom ExceptionHandler
into
implicit scope of The runRoute Wrapper or pass it to an explicit handleExceptions directive that you
have put somewhere into your route structure.
Here is an example:
import spray.util.LoggingContext
import spray.http.StatusCodes._
import spray.routing._
implicit def myExceptionHandler(implicit log: LoggingContext) =
ExceptionHandler {
case e: ArithmeticException =>
requestUri { uri =>
log.warning("Request to {} could not be handled normally", uri)
complete(InternalServerError, "Bad numbers, bad result!!!")
}
}
class MyService extends HttpServiceActor {
def receive = runRoute {
`<my-route-definition>`
}
}