Merge pull request #18023 from spray/w/java-side-documentation
Batch of Java-side documentation fills
This commit is contained in:
commit
b348691f58
18 changed files with 387 additions and 22 deletions
|
|
@ -13,7 +13,7 @@ import akka.http.javadsl.model.*;
|
|||
import akka.http.javadsl.model.headers.*;
|
||||
//#import-model
|
||||
|
||||
public class ModelSpec {
|
||||
public class ModelTest {
|
||||
@Test
|
||||
public void testConstructRequest() {
|
||||
//#construct-request
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl;
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
//#high-level-server-example
|
||||
import akka.actor.ActorSystem;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl;
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.http.impl.util.Util;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl;
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.testkit;
|
||||
|
||||
//#simple-app
|
||||
import akka.http.javadsl.server.*;
|
||||
import akka.http.javadsl.server.values.Parameters;
|
||||
|
||||
public class MyAppService extends HttpApp {
|
||||
RequestVal<Double> x = Parameters.doubleValue("x");
|
||||
RequestVal<Double> y = Parameters.doubleValue("y");
|
||||
|
||||
public RouteResult add(RequestContext ctx, double x, double y) {
|
||||
return ctx.complete("x + y = " + (x + y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Route createRoute() {
|
||||
return
|
||||
route(
|
||||
get(
|
||||
pathPrefix("calculator").route(
|
||||
path("add").route(
|
||||
handleReflectively(this, "add", x, y)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
//#simple-app
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.testkit;
|
||||
|
||||
//#simple-app-testing
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestkitExampleTest extends JUnitRouteTest {
|
||||
TestRoute appRoute = testRoute(new MyAppService().createRoute());
|
||||
|
||||
@Test
|
||||
public void testCalculatorAdd() {
|
||||
// test happy path
|
||||
appRoute.run(HttpRequest.GET("/calculator/add?x=4.2&y=2.3"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("x + y = 6.5");
|
||||
|
||||
// test responses to potential errors
|
||||
appRoute.run(HttpRequest.GET("/calculator/add?x=3.2"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND) // 404
|
||||
.assertEntity("Request is missing required query parameter 'y'");
|
||||
|
||||
// test responses to potential errors
|
||||
appRoute.run(HttpRequest.GET("/calculator/add?x=3.2&y=three"))
|
||||
.assertStatusCode(StatusCodes.BAD_REQUEST)
|
||||
.assertEntity("The query parameter 'y' was malformed:\n" +
|
||||
"'three' is not a valid 64-bit floating point value");
|
||||
}
|
||||
}
|
||||
//#simple-app-testing
|
||||
|
|
@ -13,7 +13,7 @@ Overview
|
|||
Since akka-http-core provides the central HTTP data structures you will find the following import in quite a
|
||||
few places around the code base (and probably your own code as well):
|
||||
|
||||
.. includecode:: ../code/docs/http/javadsl/ModelSpec.java
|
||||
.. includecode:: ../code/docs/http/javadsl/ModelTest.java
|
||||
:include: import-model
|
||||
|
||||
This brings all of the most relevant types in scope, mainly:
|
||||
|
|
@ -50,7 +50,7 @@ An ``HttpRequest`` consists of
|
|||
|
||||
Here are some examples how to construct an ``HttpRequest``:
|
||||
|
||||
.. includecode:: ../code/docs/http/javadsl/ModelSpec.java
|
||||
.. includecode:: ../code/docs/http/javadsl/ModelTest.java
|
||||
:include: construct-request
|
||||
|
||||
In its basic form ``HttpRequest.create`` creates an empty default GET request without headers which can then be
|
||||
|
|
@ -71,7 +71,7 @@ An ``HttpResponse`` consists of
|
|||
|
||||
Here are some examples how to construct an ``HttpResponse``:
|
||||
|
||||
.. includecode:: ../code/docs/http/javadsl/ModelSpec.java
|
||||
.. includecode:: ../code/docs/http/javadsl/ModelTest.java
|
||||
:include: construct-response
|
||||
|
||||
In addition to the simple ``HttpEntities.create`` methods which create an entity from a fixed ``String`` or ``ByteString``
|
||||
|
|
@ -169,7 +169,7 @@ as a ``RawHeader`` (which is essentially a String/String name/value pair).
|
|||
|
||||
See these examples of how to deal with headers:
|
||||
|
||||
.. includecode:: ../code/docs/http/javadsl/ModelSpec.java
|
||||
.. includecode:: ../code/docs/http/javadsl/ModelTest.java
|
||||
:include: headers
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -91,5 +91,5 @@ Predefined path matchers allow extraction of various types of values:
|
|||
|
||||
Here's a collection of path matching examples:
|
||||
|
||||
.. includecode:: ../../../code/docs/http/javadsl/PathDirectiveExampleTest.java
|
||||
.. includecode:: ../../../code/docs/http/javadsl/server/PathDirectiveExampleTest.java
|
||||
:include: path-examples
|
||||
|
|
@ -102,4 +102,42 @@ static methods. The referenced method must be publicly accessible.
|
|||
Deferring Result Creation
|
||||
-------------------------
|
||||
|
||||
TODO
|
||||
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 ``Future<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 ``Future<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-java8/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 ``Future<RouteResult>``:
|
||||
|
||||
.. includecode:: /../../akka-http-tests-java8/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 ``Future.map`` and
|
||||
returns the resulting ``Future<RouteResult>``.
|
||||
|
||||
Otherwise, you can also still use ``handleWithN`` and use ``RequestContext.completeWith`` to "convert" a
|
||||
``Future<RouteResult>`` into a ``RouteResult`` as shown here:
|
||||
|
||||
.. includecode:: /../../akka-http-tests-java8/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-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
|
||||
:include: async-example-full
|
||||
|
|
|
|||
|
|
@ -14,4 +14,5 @@ To use the high-level API you need to add a dependency to the ``akka-http-experi
|
|||
request-vals/index
|
||||
handlers
|
||||
marshalling
|
||||
testkit
|
||||
json-jackson-support
|
||||
|
|
@ -7,7 +7,7 @@ The Akka HTTP :ref:`http-low-level-server-side-api-java` provides a ``Flow``- or
|
|||
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/HttpServerExampleDocTest.java
|
||||
.. includecode:: ../../code/docs/http/javadsl/server/HttpServerExampleDocTest.java
|
||||
:include: request-handler
|
||||
|
||||
While it'd be perfectly possible to define a complete REST API service purely by inspecting the incoming
|
||||
|
|
@ -21,7 +21,7 @@ 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
|
||||
.. includecode:: ../../code/docs/http/javadsl/server/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``
|
||||
|
|
@ -68,4 +68,9 @@ to HTTP entities.
|
|||
|
||||
Read more about :ref:`marshalling-java`.
|
||||
|
||||
akka-http contains a testkit that simplifies testing routes. It allows to run test-requests against (sub-)routes
|
||||
quickly without running them over the network and helps with writing assertions on HTTP response properties.
|
||||
|
||||
Read more about :ref:`http-testkit-java`.
|
||||
|
||||
.. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
|
||||
|
|
|
|||
80
akka-docs-dev/rst/java/http/routing-dsl/testkit.rst
Normal file
80
akka-docs-dev/rst/java/http/routing-dsl/testkit.rst
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
.. _http-testkit-java:
|
||||
|
||||
Route Testkit
|
||||
=============
|
||||
|
||||
akka-http has a testkit that provides a convenient way of testing your routes with JUnit. It allows
|
||||
running requests against a route (without hitting the network) and provides means to assert against
|
||||
response properties in a compact way.
|
||||
|
||||
To use the testkit you need to take these steps:
|
||||
|
||||
* add a dependency to the ``akka-http-testkit-experimental`` module
|
||||
* derive the test class from ``JUnitRouteTest``
|
||||
* wrap the route under test with ``RouteTest.testRoute`` to create a ``TestRoute``
|
||||
* run requests against the route using ``TestRoute.run(request)`` which will return
|
||||
a ``TestResponse``
|
||||
* use the methods of ``TestResponse`` to assert on properties of the response
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
To see the testkit in action consider the following simple calculator app service:
|
||||
|
||||
.. includecode:: ../../code/docs/http/javadsl/server/testkit/MyAppService.java
|
||||
:include: simple-app
|
||||
|
||||
The app extends from ``HttpApp`` which brings all of the directives into scope. Method ``createRoute``
|
||||
needs to be implemented to return the complete route of the app.
|
||||
|
||||
Here's how you would test that service:
|
||||
|
||||
.. includecode:: ../../code/docs/http/javadsl/server/testkit/TestkitExampleTest.java
|
||||
:include: simple-app-testing
|
||||
|
||||
|
||||
Writing Asserting against the HttpResponse
|
||||
------------------------------------------
|
||||
|
||||
The testkit supports a fluent DSL to write compact assertions on the response by chaining assertions
|
||||
using "dot-syntax". To simplify working with streamed responses the entity of the response is first "strictified", i.e.
|
||||
entity data is collected into a single ``ByteString`` and provided the entity is supplied as an ``HttpEntityStrict``. This
|
||||
allows to write several assertions against the same entity data which wouldn't (necessarily) be possible for the
|
||||
streamed version.
|
||||
|
||||
All of the defined assertions provide HTTP specific error messages aiding in diagnosing problems.
|
||||
|
||||
Currently, these methods are defined on ``TestResponse`` to assert on the response:
|
||||
|
||||
=================================================================== =======================================================================
|
||||
Assertion Description
|
||||
=================================================================== =======================================================================
|
||||
``assertStatusCode(int expectedCode)`` Asserts that the numeric response status code equals the expected one
|
||||
``assertStatusCode(StatusCode expectedCode)`` Asserts that the response ``StatusCode`` equals the expected one
|
||||
``assertMediaType(String expectedType)`` Asserts that the media type part of the response's content type matches
|
||||
the given String
|
||||
``assertMediaType(MediaType expectedType)`` Asserts that the media type part of the response's content type matches
|
||||
the given ``MediaType``
|
||||
``assertEntity(String expectedStringContent)`` Asserts that the entity data interpreted as UTF8 equals the expected
|
||||
String
|
||||
``assertEntityBytes(ByteString expectedBytes)`` Asserts that the entity data bytes equal the expected ones
|
||||
``assertEntityAs(Unmarshaller<T> unmarshaller, expectedValue: T)`` Asserts that the entity data if unmarshalled with the given marshaller
|
||||
equals the given value
|
||||
``assertHeaderExists(HttpHeader expectedHeader)`` Asserts that the response contains an HttpHeader instance equal to the
|
||||
expected one
|
||||
``assertHeaderKindExists(String expectedHeaderName)`` Asserts that the response contains a header with the expected name
|
||||
``assertHeader(String name, String expectedValue)`` Asserts that the response contains a header with the given name and
|
||||
value.
|
||||
=================================================================== =======================================================================
|
||||
|
||||
It's, of course, possible to use any other means of writing assertions by inspecting the properties the response
|
||||
manually. As written above, ``TestResponse.entity`` and ``TestResponse.response`` return strict versions of the
|
||||
entity data.
|
||||
|
||||
Supporting Custom Test Frameworks
|
||||
---------------------------------
|
||||
|
||||
Adding support for a custom test framework is achieved by creating new superclass analogous to
|
||||
``JUnitRouteTest`` for writing tests with the custom test framwork deriving from ``akka.http.javadsl.testkit.RouteTest``
|
||||
and implementing its abstract methods. This will allow users of the test framework to use ``testRoute`` and
|
||||
to write assertions using the assertion methods defined on ``TestResponse``.
|
||||
|
|
@ -62,7 +62,7 @@ Starting and Stopping
|
|||
On the most basic level an Akka HTTP server is bound by invoking the ``bind`` method of the `akka.http.javadsl.Http`_
|
||||
extension:
|
||||
|
||||
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleDocTest.java
|
||||
.. includecode:: ../../code/docs/http/javadsl/server/HttpServerExampleDocTest.java
|
||||
:include: binding-example
|
||||
|
||||
Arguments to the ``Http().bind`` method specify the interface and port to bind to and register interest in handling
|
||||
|
|
@ -99,7 +99,7 @@ Requests are handled by calling one of the ``handleWithXXX`` methods with a hand
|
|||
|
||||
Here is a complete example:
|
||||
|
||||
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleDocTest.java
|
||||
.. includecode:: ../../code/docs/http/javadsl/server/HttpServerExampleDocTest.java
|
||||
:include: full-server-example
|
||||
|
||||
In this example, a request is handled by transforming the request stream with a function ``Function<HttpRequest, HttpResponse>``
|
||||
|
|
@ -149,8 +149,12 @@ optional ``httpsContext`` parameter, which can receive the HTTPS configuration i
|
|||
instance.
|
||||
If defined encryption is enabled on all accepted connections. Otherwise it is disabled (which is the default).
|
||||
|
||||
.. _http-server-layer-java:
|
||||
|
||||
Stand-Alone HTTP Layer Usage
|
||||
----------------------------
|
||||
|
||||
// TODO
|
||||
It is currently only possible to use the HTTP server layer with Scala in a stand-alone fashion.
|
||||
See :ref:`http-server-layer-scala` and `#18027`_ for the plan to add Java support.
|
||||
|
||||
.. _`#18027`: https://github.com/akka/akka/issues/18027
|
||||
|
|
@ -150,6 +150,7 @@ optional ``httpsContext`` parameter, which can receive the HTTPS configuration i
|
|||
instance.
|
||||
If defined encryption is enabled on all accepted connections. Otherwise it is disabled (which is the default).
|
||||
|
||||
.. _http-server-layer-scala:
|
||||
|
||||
Stand-Alone HTTP Layer Usage
|
||||
----------------------------
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import scala.concurrent.duration._
|
|||
import akka.stream.ActorMaterializer
|
||||
import akka.http.scaladsl.server
|
||||
import akka.http.javadsl.model.HttpRequest
|
||||
import akka.http.javadsl.server.{ AllDirectives, Route, Directives }
|
||||
import akka.http.javadsl.server.{ HttpApp, AllDirectives, Route, Directives }
|
||||
import akka.http.impl.util.JavaMapping.Implicits._
|
||||
import akka.http.impl.server.RouteImplementation
|
||||
import akka.http.scaladsl.model.HttpResponse
|
||||
|
|
@ -39,6 +39,9 @@ abstract class RouteTest extends AllDirectives {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a list of route alternatives with testing support.
|
||||
*/
|
||||
@varargs
|
||||
def testRoute(first: Route, others: Route*): TestRoute =
|
||||
new TestRoute {
|
||||
|
|
@ -47,5 +50,10 @@ abstract class RouteTest extends AllDirectives {
|
|||
def run(request: HttpRequest): TestResponse = runRoute(underlying, request)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [[TestRoute]] for the main route of an [[HttpApp]].
|
||||
*/
|
||||
def testAppRoute(app: HttpApp): TestRoute = testRoute(app.createRoute)
|
||||
|
||||
protected def createTestResponse(response: HttpResponse): TestResponse
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,49 +21,124 @@ import akka.http.javadsl.model._
|
|||
* A wrapper for responses
|
||||
*/
|
||||
abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration)(implicit ec: ExecutionContext, materializer: ActorMaterializer) {
|
||||
lazy val entity: HttpEntityStrict =
|
||||
_response.entity.toStrict(awaitAtMost).awaitResult(awaitAtMost)
|
||||
/**
|
||||
* Returns the strictified entity of the response. It will be strictified on first access.
|
||||
*/
|
||||
lazy val entity: HttpEntityStrict = _response.entity.toStrict(awaitAtMost).awaitResult(awaitAtMost)
|
||||
|
||||
/**
|
||||
* Returns a copy of the underlying response with the strictified entity.
|
||||
*/
|
||||
lazy val response: HttpResponse = _response.withEntity(entity)
|
||||
|
||||
// FIXME: add header getters / assertions
|
||||
|
||||
/**
|
||||
* Returns the media-type of the the response's content-type
|
||||
*/
|
||||
def mediaType: MediaType = extractFromResponse(_.entity.contentType.mediaType)
|
||||
|
||||
/**
|
||||
* Returns a string representation of the media-type of the the response's content-type
|
||||
*/
|
||||
def mediaTypeString: String = mediaType.toString
|
||||
|
||||
/**
|
||||
* Returns the bytes of the response entity
|
||||
*/
|
||||
def entityBytes: ByteString = entity.data()
|
||||
|
||||
/**
|
||||
* Returns the entity of the response unmarshalled with the given ``Unmarshaller``.
|
||||
*/
|
||||
def entityAs[T](unmarshaller: Unmarshaller[T]): T =
|
||||
Unmarshal(response)
|
||||
.to(unmarshaller.asInstanceOf[UnmarshallerImpl[T]].scalaUnmarshaller(ec, materializer), ec)
|
||||
.awaitResult(awaitAtMost)
|
||||
|
||||
/**
|
||||
* Returns the entity of the response interpreted as an UTF-8 encoded string.
|
||||
*/
|
||||
def entityAsString: String = entity.data().utf8String
|
||||
|
||||
/**
|
||||
* Returns the [[StatusCode]] of the response.
|
||||
*/
|
||||
def status: StatusCode = response.status.asJava
|
||||
|
||||
/**
|
||||
* Returns the numeric status code of the response.
|
||||
* @return
|
||||
*/
|
||||
def statusCode: Int = response.status.intValue
|
||||
|
||||
/**
|
||||
* Returns the first header of the response which is of the given class.
|
||||
*/
|
||||
def header[T <: HttpHeader](clazz: Class[T]): T =
|
||||
response.header(ClassTag(clazz))
|
||||
.getOrElse(fail(s"Expected header of type ${clazz.getSimpleName} but wasn't found."))
|
||||
|
||||
/**
|
||||
* Assert on the numeric status code.
|
||||
*/
|
||||
def assertStatusCode(expected: Int): TestResponse =
|
||||
assertStatusCode(StatusCodes.get(expected))
|
||||
|
||||
/**
|
||||
* Assert on the status code.
|
||||
*/
|
||||
def assertStatusCode(expected: StatusCode): TestResponse =
|
||||
assertEqualsKind(expected, status, "status code")
|
||||
|
||||
/**
|
||||
* Assert on the media type of the response.
|
||||
*/
|
||||
def assertMediaType(expected: String): TestResponse =
|
||||
assertEqualsKind(expected, mediaTypeString, "media type")
|
||||
|
||||
/**
|
||||
* Assert on the media type of the response.
|
||||
*/
|
||||
def assertMediaType(expected: MediaType): TestResponse =
|
||||
assertEqualsKind(expected, mediaType, "media type")
|
||||
|
||||
/**
|
||||
* Assert on the response entity to be a UTF8 representation of the given string.
|
||||
*/
|
||||
def assertEntity(expected: String): TestResponse =
|
||||
assertEqualsKind(expected, entityAsString, "entity")
|
||||
|
||||
/**
|
||||
* Assert on the response entity to equal the given bytes.
|
||||
*/
|
||||
def assertEntityBytes(expected: ByteString): TestResponse =
|
||||
assertEqualsKind(expected, entityBytes, "entity")
|
||||
|
||||
/**
|
||||
* Assert on the response entity to equal the given object after applying an [[Unmarshaller]].
|
||||
*/
|
||||
def assertEntityAs[T <: AnyRef](unmarshaller: Unmarshaller[T], expected: T): TestResponse =
|
||||
assertEqualsKind(expected, entityAs(unmarshaller), "entity")
|
||||
|
||||
/**
|
||||
* Assert that a given header instance exists in the response.
|
||||
*/
|
||||
def assertHeaderExists(expected: HttpHeader): TestResponse = {
|
||||
assertTrue(response.headers.exists(_ == expected), s"Header $expected was missing.")
|
||||
this
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a header of the given type exists.
|
||||
*/
|
||||
def assertHeaderKindExists(name: String): TestResponse = {
|
||||
val lowercased = name.toRootLowerCase
|
||||
assertTrue(response.headers.exists(_.is(lowercased)), s"Expected `$name` header was missing.")
|
||||
this
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a header of the given name and value exists.
|
||||
*/
|
||||
def assertHeaderExists(name: String, value: String): TestResponse = {
|
||||
val lowercased = name.toRootLowerCase
|
||||
val headers = response.headers.filter(_.is(lowercased))
|
||||
|
|
|
|||
|
|
@ -4,14 +4,19 @@
|
|||
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.dispatch.Futures;
|
||||
import akka.dispatch.Mapper;
|
||||
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 akka.japi.function.Function;
|
||||
import org.junit.Test;
|
||||
import scala.concurrent.ExecutionContext;
|
||||
import scala.concurrent.Future;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class HandlerExampleDocTest extends JUnitRouteTest {
|
||||
@Test
|
||||
|
|
@ -212,4 +217,83 @@ public class HandlerExampleDocTest extends JUnitRouteTest {
|
|||
.assertEntity("x * y = 115");
|
||||
//#reflective-example-full
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeferredResultAsyncHandler() {
|
||||
//#async-example-full
|
||||
//#async-service-definition
|
||||
class CalculatorService {
|
||||
public Future<Integer> multiply(final int x, final int y, ExecutionContext ec) {
|
||||
return akka.dispatch.Futures.future(() -> x * y, ec);
|
||||
}
|
||||
|
||||
public Future<Integer> add(final int x, final int y, ExecutionContext ec) {
|
||||
return akka.dispatch.Futures.future(() -> x + y, ec);
|
||||
}
|
||||
}
|
||||
//#async-service-definition
|
||||
|
||||
class TestHandler extends akka.http.javadsl.server.AllDirectives {
|
||||
RequestVal<Integer> xParam = Parameters.intValue("x");
|
||||
RequestVal<Integer> yParam = Parameters.intValue("y");
|
||||
|
||||
//#async-handler-1
|
||||
// would probably be injected or passed at construction time in real code
|
||||
CalculatorService calculatorService = new CalculatorService();
|
||||
public Future<RouteResult> multiplyAsync(final RequestContext ctx, int x, int y) {
|
||||
Future<Integer> result = calculatorService.multiply(x, y, ctx.executionContext());
|
||||
Mapper<Integer, RouteResult> func = new Mapper<Integer, RouteResult>() {
|
||||
@Override
|
||||
public RouteResult apply(Integer product) {
|
||||
return ctx.complete("x * y = " + product);
|
||||
}
|
||||
}; // cannot be written as lambda, unfortunately
|
||||
return result.map(func, ctx.executionContext());
|
||||
}
|
||||
Route multiplyAsyncRoute =
|
||||
path("multiply").route(
|
||||
handleWithAsync2(xParam, yParam, this::multiplyAsync)
|
||||
);
|
||||
//#async-handler-1
|
||||
|
||||
//#async-handler-2
|
||||
public RouteResult addAsync(final RequestContext ctx, int x, int y) {
|
||||
Future<Integer> result = calculatorService.add(x, y, ctx.executionContext());
|
||||
Mapper<Integer, RouteResult> func = new Mapper<Integer, RouteResult>() {
|
||||
@Override
|
||||
public RouteResult apply(Integer sum) {
|
||||
return ctx.complete("x + y = " + sum);
|
||||
}
|
||||
}; // cannot be written as lambda, unfortunately
|
||||
return ctx.completeWith(result.map(func, ctx.executionContext()));
|
||||
}
|
||||
Route addAsyncRoute =
|
||||
path("add").route(
|
||||
handleWith2(xParam, yParam, this::addAsync)
|
||||
);
|
||||
//#async-handler-2
|
||||
|
||||
Route createRoute() {
|
||||
return route(
|
||||
get(
|
||||
pathPrefix("calculator").route(
|
||||
multiplyAsyncRoute,
|
||||
addAsyncRoute
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 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=23&y=5"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("x + y = 28");
|
||||
//#async-example-full
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import akka.http.scaladsl.Http.ServerBinding
|
|||
abstract class HttpApp
|
||||
extends AllDirectives
|
||||
with HttpServiceBase {
|
||||
protected def createRoute(): Route
|
||||
def createRoute(): Route
|
||||
|
||||
/**
|
||||
* Starts an HTTP server on the given interface and port. Creates the route by calling the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue