.. _routes-java: Routes ====== The "Route" is the central concept of Akka HTTP's Routing DSL. All the structures you build with the DSL, no matter whether they consists of a single line or span several hundred lines, are functions turning a ``RequestContext`` into a ``CompletionStage``. A ``Route`` itself is a function that operates on a ``RequestContext`` and returns a ``RouteResult``. The ``RequestContext`` is a data structure that contains the current request and auxiliary data like the so far unmatched path of the request URI that gets passed through the route structure. It also contains the current ``ExecutionContext`` and ``akka.stream.Materializer``, so that these don't have to be passed around manually. Generally when a route receives a request (or rather a ``RequestContext`` for it) it can do one of these things: - Complete the request by returning the value of ``requestContext.complete(...)`` - Reject the request by returning the value of ``requestContext.reject(...)`` (see :ref:`rejections-java`) - Fail the request by returning the value of ``requestContext.fail(...)`` or by just throwing an exception (see :ref:`exception-handling-java`) - Do any kind of asynchronous processing and instantly return a ``Future[RouteResult]`` to be eventually completed later The first case is pretty clear, by calling ``complete`` a given response is sent to the client as reaction to the request. In the second case "reject" means that the route does not want to handle the request. You'll see further down in the section about route composition what this is good for. A ``Route`` can be "sealed" using ``Route.seal``, which relies on the in-scope ``RejectionHandler`` and ``ExceptionHandler`` instances to convert rejections and exceptions into appropriate HTTP responses for the client. Using ``Route.handlerFlow`` or ``Route.asyncHandler`` a ``Route`` can be lifted into a handler ``Flow`` or async handler function to be used with a ``bindAndHandleXXX`` call from the :ref:`http-low-level-server-side-api`. .. _request-context-java: RequestContext -------------- The request context wraps an ``HttpRequest`` instance to enrich it with additional information that are typically required by the routing logic, like an ``ExecutionContext``, ``Materializer``, ``LoggingAdapter`` and the configured ``RoutingSettings``. It also contains the ``unmatchedPath``, a value that describes how much of the request URI has not yet been matched by a :ref:`Path Directive `. The ``RequestContext`` itself is immutable but contains several helper methods which allow for convenient creation of modified copies. .. _route-result-java: RouteResult ----------- The ``RouteResult`` is an opaque structure that represents possible results of evaluating a route. A ``RouteResult`` can only be created by using one of the methods of the ``RequestContext``. A result can either be a response, if it was generated by one of the ``completeX`` methods, or a rejection that contains information about why the route could not handle the request. Composing Routes ---------------- Routes are composed to form the route tree in two principle ways. A route can be wrapped by a "Directive" which adds some behavioral aspect to its wrapped "inner route". In the Java DSL, a Directive is a method that returns a Route. In many cases, a Directive method will have an inner route argument that is invoked when its semantics decide to do so, e.g. when a URL path is matched. Example topics for directives include: * filtering requests to decide which requests will get to the inner route * transforming the request before passing it to the inner route * transforming the response (or more generally the route result) received from the inner route * applying side-effects around inner route processing, such as measuring the time taken to run the inner route The other way of composition is defining a list of ``Route`` alternatives. Alternative routes are tried one after the other until one route "accepts" the request and provides a response. Otherwise, a route can also "reject" a request, in which case further alternatives are explored. Alternatives are specified by passing a list of routes to to ``RouteDirectives.route()``. .. _The Routing Tree-java: The Routing Tree ---------------- Essentially, when you combine routes via nesting and alternative, you build a routing structure that forms a tree. When a request comes in it is injected into this tree at the root and flows down through all the branches in a depth-first manner until either some node completes it or it is fully rejected. Consider this schematic example. In place of directiveA, directiveB, etc., you can just imagine any of the available directives, e.g. matching a particular path, header or request parameter.:: import static akka.http.javadsl.server.Directives.*; val route = directiveA(route(() -> directiveB(route(() -> directiveC( ... // route 1 ), directiveD( ... // route 2 ), ... // route 3 )), directiveE( ... // route 4 ) )); Here five directives form a routing tree. - Route 1 will only be reached if directives ``a``, ``b`` and ``c`` all let the request pass through. - Route 2 will run if ``a`` and ``b`` pass, ``c`` rejects and ``d`` passes. - Route 3 will run if ``a`` and ``b`` pass, but ``c`` and ``d`` reject. Route 3 can therefore be seen as a "catch-all" route that only kicks in, if routes chained into preceding positions reject. This mechanism can make complex filtering logic quite easy to implement: simply put the most specific cases up front and the most general cases in the back.