diff --git a/akka-docs-dev/rst/java/code/docs/http/javadsl/HandlerExampleSpec.java b/akka-docs-dev/rst/java/code/docs/http/javadsl/HandlerExampleSpec.java new file mode 100644 index 0000000000..79ce476add --- /dev/null +++ b/akka-docs-dev/rst/java/code/docs/http/javadsl/HandlerExampleSpec.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2009-2015 Typesafe Inc. + */ + +package docs.http.javadsl; + +import akka.http.javadsl.model.HttpRequest; +import akka.http.javadsl.server.*; +import akka.http.javadsl.server.values.Parameters; +import akka.http.javadsl.server.values.PathMatchers; +import akka.http.javadsl.testkit.JUnitRouteTest; +import akka.http.javadsl.testkit.TestRoute; +import org.junit.Test; + +public class HandlerExampleSpec extends JUnitRouteTest { + @Test + public void testSimpleHandler() { + //#simple-handler-example-full + class TestHandler extends akka.http.javadsl.server.AllDirectives { + //#simple-handler + Handler handler = new Handler() { + @Override + public RouteResult handle(RequestContext ctx) { + return ctx.complete("This was a " + ctx.request().method().value() + + " request to "+ctx.request().getUri()); + } + }; + //#simple-handler + + Route createRoute() { + return route( + get( + handleWith(handler) + ), + post( + path("abc").route( + handleWith(handler) + ) + ) + ); + } + } + + // actual testing code + TestRoute r = testRoute(new TestHandler().createRoute()); + r.run(HttpRequest.GET("/test")) + .assertStatusCode(200) + .assertEntity("This was a GET request to /test"); + + r.run(HttpRequest.POST("/test")) + .assertStatusCode(404); + + r.run(HttpRequest.POST("/abc")) + .assertStatusCode(200) + .assertEntity("This was a POST request to /abc"); + //#simple-handler-example-full + } + + @Test + public void testCalculator() { + //#handler2-example-full + class TestHandler extends akka.http.javadsl.server.AllDirectives { + RequestVal xParam = Parameters.intValue("x"); + RequestVal yParam = Parameters.intValue("y"); + + RequestVal xSegment = PathMatchers.integerNumber(); + RequestVal ySegment = PathMatchers.integerNumber(); + + //#handler2 + Handler2 multiply = + new Handler2() { + @Override + public RouteResult handle(RequestContext ctx, Integer x, Integer y) { + int result = x * y; + return ctx.complete("x * y = " + result); + } + }; + + Route multiplyXAndYParam = handleWith(xParam, yParam, multiply); + //#handler2 + + Route createRoute() { + return route( + get( + pathPrefix("calculator").route( + path("multiply").route( + multiplyXAndYParam + ), + path("path-multiply", xSegment, ySegment).route( + handleWith(xSegment, ySegment, multiply) + ) + ) + ) + ); + } + } + + // actual testing code + TestRoute r = testRoute(new TestHandler().createRoute()); + r.run(HttpRequest.GET("/calculator/multiply?x=12&y=42")) + .assertStatusCode(200) + .assertEntity("x * y = 504"); + + r.run(HttpRequest.GET("/calculator/path-multiply/23/5")) + .assertStatusCode(200) + .assertEntity("x * y = 115"); + //#handler2-example-full + } + + @Test + public void testCalculatorReflective() { + //#reflective-example-full + class TestHandler extends akka.http.javadsl.server.AllDirectives { + RequestVal xParam = Parameters.intValue("x"); + RequestVal yParam = Parameters.intValue("y"); + + RequestVal xSegment = PathMatchers.integerNumber(); + RequestVal ySegment = PathMatchers.integerNumber(); + + + //#reflective + public RouteResult multiply(RequestContext ctx, Integer x, Integer y) { + int result = x * y; + return ctx.complete("x * y = " + result); + } + + Route multiplyXAndYParam = handleWith(this, "multiply", xParam, yParam); + //#reflective + + Route createRoute() { + return route( + get( + pathPrefix("calculator").route( + path("multiply").route( + multiplyXAndYParam + ), + path("path-multiply", xSegment, ySegment).route( + handleWith(this, "multiply", xSegment, ySegment) + ) + ) + ) + ); + } + } + + // actual testing code + TestRoute r = testRoute(new TestHandler().createRoute()); + r.run(HttpRequest.GET("/calculator/multiply?x=12&y=42")) + .assertStatusCode(200) + .assertEntity("x * y = 504"); + + r.run(HttpRequest.GET("/calculator/path-multiply/23/5")) + .assertStatusCode(200) + .assertEntity("x * y = 115"); + //#reflective-example-full + } +} diff --git a/akka-docs-dev/rst/java/http/routing-dsl/handlers.rst b/akka-docs-dev/rst/java/http/routing-dsl/handlers.rst new file mode 100644 index 0000000000..57b0710f3d --- /dev/null +++ b/akka-docs-dev/rst/java/http/routing-dsl/handlers.rst @@ -0,0 +1,88 @@ +.. _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 + * with a number ``n`` of ``RequestVal`` arguments and a ``HandlerN`` argument + * with a ``Class`` and/or instance and a method name String argument and a variable number of ``RequestVal`` + 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:: ../../code/docs/http/javadsl/HandlerExampleSpec.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:: ../../code/docs/http/javadsl/HandlerExampleSpec.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:: ../../code/docs/http/javadsl/HandlerExampleSpec.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:: ../../code/docs/http/javadsl/HandlerExampleSpec.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 +------------------ + +In Java 8 handlers can be provided as function literals. The example from before then looks like this: + +.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleSpec.java + :include: handler2-example-full + + +Providing Handlers by Reflection +-------------------------------- + +Using Java before Java 8, writing out handlers as (anonymous) classes can be unwieldy. Therefore, ``handleWith`` +overloads are provided that allow writing handler as simple methods and specifying them by name: + +.. includecode:: ../../code/docs/http/javadsl/HandlerExampleSpec.java + :include: reflective + +The complete calculator example can then be written like this: + +.. includecode:: ../../code/docs/http/javadsl/HandlerExampleSpec.java + :include: reflective-example-full + +There are alternative overloads for ``handleWith`` that take a ``Class`` instead of an object instance to refer to +static methods. The referenced method must be publicly accessible. + +Deferring Result Creation +------------------------- + +TODO \ No newline at end of file diff --git a/akka-docs-dev/rst/java/http/routing-dsl/index.rst b/akka-docs-dev/rst/java/http/routing-dsl/index.rst index 24a841c0c7..2ec80185ba 100644 --- a/akka-docs-dev/rst/java/http/routing-dsl/index.rst +++ b/akka-docs-dev/rst/java/http/routing-dsl/index.rst @@ -12,3 +12,6 @@ High-level Server-Side API routes directives/index request-vals/index + handlers + path-matchers + marshalling diff --git a/akka-docs-dev/rst/java/http/routing-dsl/marshalling.rst b/akka-docs-dev/rst/java/http/routing-dsl/marshalling.rst new file mode 100644 index 0000000000..fd1c2ec9b9 --- /dev/null +++ b/akka-docs-dev/rst/java/http/routing-dsl/marshalling.rst @@ -0,0 +1,6 @@ +.. _marshalling-java: + +Marshalling & Unmarshalling +=========================== + +TODO \ No newline at end of file diff --git a/akka-docs-dev/rst/java/http/routing-dsl/overview.rst b/akka-docs-dev/rst/java/http/routing-dsl/overview.rst index 42979b6d54..3828ad8a42 100644 --- a/akka-docs-dev/rst/java/http/routing-dsl/overview.rst +++ b/akka-docs-dev/rst/java/http/routing-dsl/overview.rst @@ -56,6 +56,12 @@ fields, details of the request like headers, URI, the entity, or authentication Read more about :ref:`request-vals-java`. +The actual application-defined processing of a request is defined with a ``Handler`` instance or by specifying +a handling method with reflection. A handler can receive the value of any request values and is converted into +a ``Route`` by using one of the ``BasicDirectives.handleWith`` directives. + +Read more about :ref:`handlers-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. diff --git a/akka-docs-dev/rst/java/http/routing-dsl/path-matchers.rst b/akka-docs-dev/rst/java/http/routing-dsl/path-matchers.rst new file mode 100644 index 0000000000..59a3834976 --- /dev/null +++ b/akka-docs-dev/rst/java/http/routing-dsl/path-matchers.rst @@ -0,0 +1,6 @@ +.. _pathmatcher-dsl-java: + +The PathMatcher DSL +=================== + +TODO \ No newline at end of file diff --git a/akka-http-core/src/main/scala/akka/http/impl/model/JavaUri.scala b/akka-http-core/src/main/scala/akka/http/impl/model/JavaUri.scala index fd9e096849..6fe329a5d1 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/model/JavaUri.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/model/JavaUri.scala @@ -78,4 +78,6 @@ case class JavaUri(uri: sm.Uri) extends jm.Uri { def fragment(fragment: Option[String]): jm.Uri = t(_.copy(fragment = fragment)) def fragment(fragment: String): jm.Uri = t(_.withFragment(fragment)) + + override def toString: String = uri.toString } \ No newline at end of file diff --git a/akka-http-tests-java8/src/test/java/AllJavaTests.java b/akka-http-tests-java8/src/test/java/AllJavaTests.java index be754e78a5..bb81c717af 100644 --- a/akka-http-tests-java8/src/test/java/AllJavaTests.java +++ b/akka-http-tests-java8/src/test/java/AllJavaTests.java @@ -3,10 +3,14 @@ */ import akka.http.javadsl.server.HandlerBindingTest; +import docs.http.javadsl.server.HandlerExampleSpec; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) -@Suite.SuiteClasses(HandlerBindingTest.class) +@Suite.SuiteClasses({ + HandlerBindingTest.class, + HandlerExampleSpec.class +}) public class AllJavaTests { } diff --git a/akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleSpec.java b/akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleSpec.java new file mode 100644 index 0000000000..2f5495d964 --- /dev/null +++ b/akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleSpec.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009-2015 Typesafe Inc. + */ + +package docs.http.javadsl.server; + +import akka.http.javadsl.model.HttpRequest; +import akka.http.javadsl.server.*; +import akka.http.javadsl.server.values.Parameters; +import akka.http.javadsl.testkit.JUnitRouteTest; +import akka.http.javadsl.testkit.TestRoute; +import org.junit.Test; + +public class HandlerExampleSpec extends JUnitRouteTest { + @Test + public void testCalculator() { + //#handler2-example-full + class TestHandler extends akka.http.javadsl.server.AllDirectives { + RequestVal xParam = Parameters.intValue("x"); + RequestVal yParam = Parameters.intValue("y"); + + //#handler2 + Handler2 multiply = + (ctx, x, y) -> ctx.complete("x * y = " + (x * y)); + + Route multiplyXAndYParam = handleWith(xParam, yParam, multiply); + //#handler2 + + Route createRoute() { + return route( + get( + pathPrefix("calculator").route( + path("multiply").route( + multiplyXAndYParam + ), + path("add").route( + handleWith(xParam, yParam, + (ctx, x, y) -> ctx.complete("x + y = " + (x + y))) + ) + ) + ) + ); + } + } + + // actual testing code + TestRoute r = testRoute(new TestHandler().createRoute()); + r.run(HttpRequest.GET("/calculator/multiply?x=12&y=42")) + .assertStatusCode(200) + .assertEntity("x * y = 504"); + + r.run(HttpRequest.GET("/calculator/add?x=12&y=42")) + .assertStatusCode(200) + .assertEntity("x + y = 54"); + //#handler2-example-full + } +} \ No newline at end of file diff --git a/akka-http/src/main/scala/akka/http/javadsl/server/Handler.scala b/akka-http/src/main/scala/akka/http/javadsl/server/Handler.scala index e5d3823a90..ec878011af 100644 --- a/akka-http/src/main/scala/akka/http/javadsl/server/Handler.scala +++ b/akka-http/src/main/scala/akka/http/javadsl/server/Handler.scala @@ -11,9 +11,11 @@ package akka.http.javadsl.server * Use the methods in [[RequestContext]] to create a [[RouteResult]]. A handler mustn't * return [[null]] as the result. */ +//#handler trait Handler { def handle(ctx: RequestContext): RouteResult } +//#handler /** * A route handler with one additional argument.