Exception Handling

Exceptions thrown during route execution bubble up through the route structure to the next enclosing handleExceptions directive or the top of your route structure.

Similarly to the way that Rejections are handled the handleExceptions directive delegates the actual job of converting an exception to its argument, an ExceptionHandler.

An ExceptionHandler is a partial function, so 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. At the root of the route tree any still unhandled exception will be dealt with by the top-level handler which always handles all exceptions.

Route.seal internally wraps its argument route with the handleExceptions directive in order to “catch” and handle any exception.

So, if you’d like to customize the way certain exceptions are handled you need to write a custom ExceptionHandler. Once you have defined your custom ExceptionHandler you can supply it as argument to the handleExceptions directive. That will apply your handler to the inner route given to that directive.

Here is an example for wiring up a custom handler via handleExceptions: Route class’s seal() method internally wraps its argument route with the handleExceptions directive in order to “catch” and handle any exception.

So, if you’d like to customize the way certain exceptions are handled you need to write a custom ExceptionHandler. Once you have defined your custom ExceptionHandler you have two options.

  1. Pass it to the seal() method of the Route class
  2. Supply it as an argument to handleExceptions directive

In the first case your handler will be “sealed” (which means that it will receive the default handler as a fallback for all cases your handler doesn’t handle itself) and used for all exceptions that are not handled within the route structure itself.

The second case allows you to restrict the applicability of your handler to certain branches of your route structure.

Here is an example for wiring up a custom handler via handleExceptions:

public class ExceptionHandlerExample extends AllDirectives {
  public static void main(String[] args) throws IOException {
    final ActorSystem system = ActorSystem.create();
    final ActorMaterializer materializer = ActorMaterializer.create(system);
    final Http http = Http.get(system);

    final ExceptionHandlerExample app = new ExceptionHandlerExample();

    final Flow<HttpRequest, HttpResponse, NotUsed> routeFlow = app.createRoute().flow(system, materializer);
    final CompletionStage<ServerBinding> binding = http.bindAndHandle(routeFlow, ConnectHttp.toHost("localhost", 8080), materializer);
  }


  public Route createRoute() {
    final ExceptionHandler divByZeroHandler = ExceptionHandler.newBuilder()
      .match(ArithmeticException.class, x ->
        complete(StatusCodes.BAD_REQUEST, "You've got your arithmetic wrong, fool!"))
      .build();

    return path(PathMatchers.segment("divide").slash(integerSegment()).slash(integerSegment()), (a, b) ->
      handleExceptions(divByZeroHandler, () -> complete("The result is " + (a / b)))
    );
  }
}
The source code for this page can be found here.