=doc add lots of documentation about java-side routing API, some detail and further examples still missing

This commit is contained in:
Johannes Rudolph 2015-07-10 19:10:29 +02:00
parent 11d98a6593
commit ab38c36cba
20 changed files with 384 additions and 50 deletions

View file

@ -0,0 +1,6 @@
.. _directives-java:
Directives
==========
TODO

View file

@ -8,4 +8,7 @@ High-level Server-Side API
.. toctree::
:maxdepth: 1
overview
overview
routes
directives/index
request-vals/index

View file

@ -1,4 +1,65 @@
.. _routing-java:
Routing DSL Overview
====================
...
The Akka HTTP :ref:`http-low-level-server-side-api-java` provides a ``Flow``- or ``Function``-level interface that allows
an application to respond to incoming HTTP requests by simply mapping requests to responses
(excerpt from :ref:`Low-level server side example <http-low-level-server-side-example-java>`):
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleSpec.java
:include: request-handler
While it'd be perfectly possible to define a complete REST API service purely by inspecting the incoming
``HttpRequest`` this approach becomes somewhat unwieldy for larger services due to the amount of syntax "ceremony"
required. Also, it doesn't help in keeping your service definition as DRY_ as you might like.
As an alternative Akka HTTP provides a flexible DSL for expressing your service behavior as a structure of
composable elements (called :ref:`directives-java`) in a concise and readable way. Directives are assembled into a so called
*route structure* which, at its top-level, can be used to create a handler ``Flow`` (or, alternatively, an
async handler function) that can be directly supplied to a ``bind`` call.
Here's the complete example rewritten using the composable high-level API:
.. includecode:: ../../code/docs/http/javadsl/HighLevelServerExample.java
:include: high-level-server-example
Heart of the high-level architecture is the route tree. It is a big expression of type ``Route``
that is evaluated only once during startup time of your service. It completely describes how your service
should react to any request.
The type ``Route`` is the basic building block of the route tree. It defines if and a how a request should
be handled. Routes are composed to form the route tree in the following two ways.
A route can be wrapped by a "Directive" which adds some behavioral aspect to its wrapped "inner route". ``path("ping")`` is such
a directive that implements a path filter, i.e. it only passes control to its inner route when the unmatched path
matches ``"ping"``. Directives can be more versatile than this: A directive can also transform the request before
passing it into its inner route or transform a response that comes out of its inner route. It's a general and powerful
abstraction that allows to package any kind of HTTP processing into well-defined blocks that can be freely combined.
akka-http defines a library of predefined directives and routes for all the various aspects of dealing with
HTTP requests and responses.
Read more about :ref:`directives-java`.
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 either
to ``Directive.route()`` as in ``pathSingleSlash().route()`` or to directives that directly take a variable number
of inner routes as argument like ``get()`` here.
Read more about :ref:`routes-java`.
Another important building block is a ``RequestVal<T>``. It represents a value that can be extracted from a
request (like the URI parameter ``Parameters.stringValue("name")`` in the example) and which is then interpreted
as a value of type ``T``. Examples of HTTP aspects represented by a ``RequestVal`` are URI parameters, HTTP form
fields, details of the request like headers, URI, the entity, or authentication data.
Read more about :ref:`request-vals-java`.
Requests or responses often contain data that needs to be interpreted or rendered in some way.
Akka-http provides the abstraction of ``Marshaller`` and ``Unmarshaller`` that define how domain model objects map
to HTTP entities.
Read more about :ref:`marshalling-java`.
.. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself

View file

@ -0,0 +1,37 @@
.. _request-vals-java:
Request values
==============
A request value of type ``RequestVal<T>`` is a typed structure that represents some aspect of the request
that can be interpreted as a value of type ``T``. A ``RequestVal`` instance abstracts the knowledge about how
to extract a certain value from the request and interpret it as a ``T``. It is used in combination with
:ref:`handlers-java`.
The advantage of representing a request detail as a ``RequestVal`` instead of performing ad-hoc analysis of
a request are:
* you can define an "inventory" of HTTP primitives for your application that you can reuse in many places of your
application
* automatic handling of errors when an expected value was not found in a request or if it could not be interpreted
as the expected Java type
Note, that the Scala version of the routing DSL has no direct correspondent to RequestVals. Instead,
a Scala-side ``Directive`` can have "extractions" that are reflected in the type of the ``Directive``.
Predefined Request values
-------------------------
akka-http provides a set of predefined request values for request data commonly accessed in a web
service.
These request values are defined:
* in ``RequestVals``: request values for basic data like URI components, request method, peer address, or the entity data
* in ``Cookies``: request values representing cookies
* in ``FormFields``: request values to access form fields unmarshalled to various primitive Java types
* in ``Headers``:: request values to access request headers or header values
* ``HttpBasicAuthenticator``: an abstract class to implement to create a request value representing a HTTP basic authenticated principal
* in ``Parameters``: request values to access URI paramaters unmarshalled to various primitive Java types
* in ``PathMatchers``: request values to match and access URI path segments
* ``CustomRequestVal``: an abstract class to implement arbitrary custom request values

View file

@ -0,0 +1,90 @@
.. _routes-java:
Routes
======
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.
.. _request-context-java:
RequestContext
--------------
The ``RequestContext`` achieves two goals: it allows access to request data and it is a factory for creating a
``RouteResult``. A user-defined handler (see :ref:`handlers-java`) that is usually used at the leaf position of
the route tree receives a ``RequestContext``, evaluates its content and then returns a result generated by one of
the methods of the context.
.. _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, it can be an eventual result, i.e. a ``Future<RouteResult`` if
``completeWith`` was used 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". Such an aspect can
be
* 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
akka-http defines a library of predefined :ref:`directives-java` and routes for all the various aspects of dealing with
HTTP requests and responses.
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 either
to ``Directive.route()`` as in ``path("xyz").route()`` or to directives that directly take a variable number
of inner routes as argument like ``get()``.
.. _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::
val route =
a.route(
b.route(
c.route(
... // route 1
),
d.route(
... // route 2
),
... // route 3
),
e.route(
... // 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.