pekko/akka-docs/rst/java/http/routing-dsl/handlers.rst
Roland Kuhn 4c72495581 #19440 replace Scala Future usage with CompletionStage in javadsl
This entails:

  * adding akka.pattern.PatternCS.* to enable ask etc. with
    CompletionStage
  * changing RequestContext to offer an ExecutionContextExecutor for the
    CompletionStage.*Async combinators
  * splitting up akka.stream.Queue for JavaDSL consistency
2016-01-23 18:00:11 +01:00

143 lines
7.4 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

.. _handlers-java:
Handlers
========
Handlers implement the actual application-defined logic for a certain trace in the routing tree. Most of the leaves of
the routing tree will be routes created from handlers. Creating a ``Route`` from a handler is achieved using the
``BasicDirectives.handleWith`` overloads. They come in several forms:
* with a single ``Handler`` argument and a variable number of ``RequestVal<?>`` (may be 0)
* with a number ``n`` of ``RequestVal<T1>`` arguments and a ``HandlerN<T1, .., TN>`` argument
* with a ``Class<?>`` and/or instance and a method name String argument and a variable number of ``RequestVal<?>`` (may be 0)
arguments
Simple Handler
--------------
In its simplest form a ``Handler`` is a SAM class that defines application behavior
by inspecting the ``RequestContext`` and returning a ``RouteResult``:
.. includecode:: /../../akka-http/src/main/scala/akka/http/javadsl/server/Handler.scala
:include: handler
Such a handler inspects the ``RequestContext`` it receives and uses the ``RequestContext``'s methods to
create a response:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: simple-handler
The handler can include any kind of logic but must return a ``RouteResult`` in the end which can only
be created by using one of the ``RequestContext`` methods.
A handler instance can be used once or several times as shown in the full example:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: simple-handler-example-full
Handlers and Request Values
---------------------------
In many cases, instead of manually inspecting the request, a handler will make use of :ref:`request-vals-java`
to extract details from the request. This is possible using one of the other ``handleWith`` overloads that bind
the values of one or more request values with a ``HandlerN`` instance to produce a ``Route``:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: handler2
The handler here implements multiplication of two integers. However, it doesn't need to specify where these
parameters come from. In ``handleWith``, as many request values of the matching type have to be specified as the
handler needs. This can be seen in the full example:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: handler2-example-full
Here, the handler is again being reused. First, in creating a route that expects URI parameters ``x`` and ``y``. This
route is then used in the route structure. And second, the handler is used with another set of ``RequestVal`` in the
route structure, this time representing segments from the URI path.
Handlers in Java 8
------------------
Handlers are in fact simply classes which extend ``akka.japi.function.FunctionN`` in order to make reasoning
about the number of handled arguments easier. For example, a :class:`Handler1[String]` is simply a
``Function2[RequestContext, String, RouteResult]``. You can think of handlers as hot-dogs, where each ``T``
type represents a sausage, put between the "buns" which are ``RequestContext`` and ``RouteResult``.
In Java 8 handlers can be provided as function literals or method references. The previous example can then be written
like this:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: handler2-java8-example-full
.. note::
The reason the ``handleWith##`` methods include the number of handled values is because otherwise (if overloading would
be used, for all 22 methods) error messages generated by ``javac`` end up being very long and not readable, i.e.
if one type of a handler does not match the given values, *all* possible candidates would be printed in the error message
(22 of them), instead of just the one arity-matching method, pointing out that the type does not match.
We opted for better error messages as we feel this is more helpful when developing applications,
instead of having one overloaded method which looks nice when everything works, but procudes hard to read error
messages if something does not match up.
Providing Handlers by Reflection
--------------------------------
Using Java before Java 8, writing out handlers as (anonymous) classes can be unwieldy. Therefore, ``handleReflectively``
overloads are provided that allow writing handler as simple methods and specifying them by name:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: reflective
The complete calculator example can then be written like this:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: reflective-example-full
There are alternative overloads for ``handleReflectively`` that take a ``Class`` instead of an object instance to refer to
static methods. The referenced method must be publicly accessible.
Deferring Result Creation
-------------------------
Sometimes a handler cannot directly complete the request but needs to do some processing asynchronously. In this case
the completion of a request needs to be deferred until the result has been generated. This is supported by the routing
DSL in two ways: either you can use one of the ``handleWithAsyncN`` methods passing an ``AsyncHandlerN`` which
returns a ``CompletionStage<RouteResult>``, i.e. an eventual ``RouteResult``, or you can also use a regular handler as shown
above and use ``RequestContext.completeWith`` for completion which takes an ``CompletionStage<RouteResult>`` as an argument.
This is demonstrated in the following example. Consider a asynchronous service defined like this
(making use of Java 8 lambdas):
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: async-service-definition
Here the calculator runs the actual calculation in the background and only eventually returns the result. The HTTP
service should provide a front-end to that service without having to block while waiting for the results. As explained
above this can be done in two ways.
First, you can use ``handleWithAsyncN`` to be able to return a ``CompletionStage<RouteResult>``:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: async-handler-1
The handler invokes the service and then maps the calculation result to a ``RouteResult`` using ``CompletionStage.thenApplyAsync`` and
returns the resulting ``CompletionStage<RouteResult>``. Note that you should always explicitly provide an executor that designates
where the future transformation task is executed, using the JDKs global ForkJoinPool is not recommended.
Otherwise, you can also still use ``handleWithN`` and use ``RequestContext.completeWith`` to "convert" a
``CompletionStage<RouteResult>`` into a ``RouteResult`` as shown here:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: async-handler-2
Using this style, you can decide in your handler if you want to return a direct synchronous result or if you need
to defer completion.
Both alternatives will not block and show the same runtime behavior.
Here's the complete example:
.. includecode:: /../../akka-http-tests/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: async-example-full