* !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
116 lines
5.6 KiB
ReStructuredText
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.
|