pekko/akka-docs/rst/java/http/routing-dsl/routes.rst
Johan Andrén 29029be31d !htp #18919 #19519 New JavaDSL for Akka HTTP (#20518)
* !htt #18919 #19519 Align Java HTTP server DSL with Scala

This commits replaces the Java HTTP server DSL with a Java-8 centric one
which exposes all scala DSL concepts to be usable from Java, including
custom directives, (un)marshallers, rejections, headers, and type safety
for path and query parameters.

* Add RequestContext and RouteResult to Java DSL
fix websockets
WIP bring java docs up to date.
This applies some updates to the root-level documentation

* [htp] Fix java documentation to correctly mention timeouts

Timeouts are configured the same in Java and Scala. Hence, linking to the
scala docs for timeouts from Java.

* =htc fix optionalHeaderValueByType in Java

* =htt #20200 fix java testkit always using NoLogging instead logger

* +htt actually run new javadsl tests, allow overriding config

* =htt improve javadsl test infra with more details when fails

* =htt fix bug in wrong path matcher exposed

* +htp add missing remaining path matcher

* =htp Java DSL cookie tests fixed

* =htt Java DSL ParameterDirectivesTest fixed

Protect the tweets from scalariform

Incorrect response expectations in cache condition directives spec fixed

* =htt Path directives for Java DSL

* +!htt PathMatchers rewritten, made uniform and tests passing

* Bugfix in java reject and a little test-boyscouting

* Revert "Incorrect response expectations in cache condition directives spec fixed"

This reverts commit cd50e89d45db010309f8249b090ea654ebb11c7a.

* +htc HttpAPIsTest is compile time only, not for running
Also, moved from the client package since not strictly a client test.

SecurityDirectives passing

Two faulty tests and two actual bugs.

Fix for cache condition spec not working

* Not sending in Unit instad of the implicit magnet in the test
* HeaderMagnet now works as expected
* Java API added for - and + on DateTime

PetStore example and test fixed

* Annotations to make marshalling work without default constructor
* Made model class immutable

Incorrect tests fixed

Some scaladoc boyscouting as bonus

* =htt RequestValTest sprinkled out across multiple directive tests

Client ip extraction test with incorrect header name fixed.

* =htt Incorrect CodingDirectivesTest fixed.

* =htt Bugfix for Java Unmarshaller.firstOf and fixes to JavaRouteTest

* =htt MarshallerTest fixed

* Missing seal signature added to JavaDSL
* More consistent (with Scala) test kit setup for Java
* missing Javadocs added
* Thread.sleep in default exception handler removed

* =htt copy directive docs, prepare for finishing it up

* +htt SecurityDirectives.authorize variants and test coverage added

* +htt Custom headers in Java DSL

* =htt WIP on java docs

* +htp add missing parameterOrDefault directive
Fixed a lot of doc warnings

* =htc intense progress on javadsl docs

* =htc #20470 Link to issue about docs and fix compile error
compile, migration guide
don't mima check http-experimental

* =htt Java DSL doc warnings fixed.
Only `Could not lex literal_block` ones left now

* =htc fix mima settings

* =doc fix MethodDirectives doc test with custom method

* =htc fix coding directives spec after bad merge

* =htc fix concat being corresponding to route() in javadsl

* =htt Disable consistency check for route/concat as it fails only on ci server

* !htt Minor fixes to PathMatchers
2016-05-16 10:38:40 +02:00

116 lines
5.6 KiB
ReStructuredText

.. _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<RouteResult>``.
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 <PathDirectives>`.
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.