Merge pull request #17965 from spray/w/java-side-documentation

Java side documentation progress
This commit is contained in:
Konrad Malawski 2015-07-14 10:22:21 +02:00
commit 95e2640902
52 changed files with 1520 additions and 32 deletions

View file

@ -0,0 +1,157 @@
/*
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
*/
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<Integer> xParam = Parameters.intValue("x");
RequestVal<Integer> yParam = Parameters.intValue("y");
RequestVal<Integer> xSegment = PathMatchers.integerNumber();
RequestVal<Integer> ySegment = PathMatchers.integerNumber();
//#handler2
Handler2<Integer, Integer> multiply =
new Handler2<Integer, Integer>() {
@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<Integer> xParam = Parameters.intValue("x");
RequestVal<Integer> yParam = Parameters.intValue("y");
RequestVal<Integer> xSegment = PathMatchers.integerNumber();
RequestVal<Integer> 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
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.http.javadsl;
//#high-level-server-example
import akka.actor.ActorSystem;
import akka.http.javadsl.model.MediaTypes;
import akka.http.javadsl.server.*;
import akka.http.javadsl.server.values.Parameters;
import java.io.IOException;
public class HighLevelServerExample extends HttpApp {
public static void main(String[] args) throws IOException {
// boot up server using the route as defined below
ActorSystem system = ActorSystem.create();
// HttpApp.bindRoute expects a route being provided by HttpApp.createRoute
new HighLevelServerExample().bindRoute("localhost", 8080, system);
System.out.println("Type RETURN to exit");
System.in.read();
system.shutdown();
}
// A RequestVal is a type-safe representation of some aspect of the request.
// In this case it represents the `name` URI parameter of type String.
private RequestVal<String> name = Parameters.stringValue("name").withDefault("Mister X");
@Override
public Route createRoute() {
// This handler generates responses to `/hello?name=XXX` requests
Route helloRoute =
handleWith(name,
// in Java 8 the following becomes simply
// (ctx, name) -> ctx.complete("Hello " + name + "!")
new Handler1<String>() {
@Override
public RouteResult handle(RequestContext ctx, String name) {
return ctx.complete("Hello " + name + "!");
}
});
return
// here the complete behavior for this server is defined
route(
// only handle GET requests
get(
// matches the empty path
pathSingleSlash().route(
// return a constant string with a certain content type
complete(MediaTypes.TEXT_HTML.toContentType(),
"<html><body>Hello world!</body></html>")
),
path("ping").route(
// return a simple `text/plain` response
complete("PONG!")
),
path("hello").route(
// uses the route defined above
helloRoute
)
)
);
}
}
//#high-level-server-example

View file

@ -0,0 +1,121 @@
/*
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.http.javadsl;
import akka.actor.ActorSystem;
import akka.http.impl.util.Util;
import akka.http.javadsl.Http;
import akka.http.javadsl.IncomingConnection;
import akka.http.javadsl.ServerBinding;
import akka.http.javadsl.model.*;
import akka.http.javadsl.model.ws.Websocket;
import akka.japi.function.Function;
import akka.japi.function.Procedure;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
import org.junit.Test;
import scala.Function1;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.FiniteDuration;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
public class HttpServerExampleSpec {
public static void bindingExample() {
//#binding-example
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, Future<ServerBinding>> serverSource =
Http.get(system).bind("localhost", 8080, materializer);
Future<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(
new Procedure<IncomingConnection>() {
@Override
public void apply(IncomingConnection connection) throws Exception {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}
})).run(materializer);
//#binding-example
}
public static void fullServerExample() throws Exception {
//#full-server-example
ActorSystem system = ActorSystem.create();
//#full-server-example
try {
//#full-server-example
final Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, Future<ServerBinding>> serverSource =
Http.get(system).bind("localhost", 8080, materializer);
//#request-handler
final Function<HttpRequest, HttpResponse> requestHandler =
new Function<HttpRequest, HttpResponse>() {
private final HttpResponse NOT_FOUND =
HttpResponse.create()
.withStatus(404)
.withEntity("Unknown resource!");
@Override
public HttpResponse apply(HttpRequest request) throws Exception {
Uri uri = request.getUri();
if (request.method() == HttpMethods.GET) {
if (uri.path().equals("/"))
return
HttpResponse.create()
.withEntity(MediaTypes.TEXT_HTML.toContentType(),
"<html><body>Hello world!</body></html>");
else if (uri.path().equals("/hello")) {
String name = Util.getOrElse(uri.parameter("name"), "Mister X");
return
HttpResponse.create()
.withEntity("Hello " + name + "!");
}
else if (uri.path().equals("/ping"))
return HttpResponse.create().withEntity("PONG!");
else
return NOT_FOUND;
}
else return NOT_FOUND;
}
};
//#request-handler
Future<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(
new Procedure<IncomingConnection>() {
@Override
public void apply(IncomingConnection connection) throws Exception {
System.out.println("Accepted new connection from " + connection.remoteAddress());
connection.handleWithSyncHandler(requestHandler, materializer);
// this is equivalent to
//connection.handleWith(Flow.of(HttpRequest.class).map(requestHandler), materializer);
}
})).run(materializer);
//#full-server-example
Await.result(serverBindingFuture, new FiniteDuration(1, TimeUnit.SECONDS)); // will throw if binding fails
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
} finally {
system.shutdown();
}
}
public static void main(String[] args) throws Exception {
fullServerExample();
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.http.javadsl;
import akka.japi.Option;
import akka.util.ByteString;
import org.junit.Test;
//#import-model
import akka.http.javadsl.model.*;
import akka.http.javadsl.model.headers.*;
//#import-model
public class ModelSpec {
@Test
public void testConstructRequest() {
//#construct-request
// construct a simple GET request to `homeUri`
Uri homeUri = Uri.create("/home");
HttpRequest request1 = HttpRequest.create().withUri(homeUri);
// construct simple GET request to "/index" using helper methods
HttpRequest request2 = HttpRequest.GET("/index");
// construct simple POST request containing entity
ByteString data = ByteString.fromString("abc");
HttpRequest postRequest1 = HttpRequest.POST("/receive").withEntity(data);
// customize every detail of HTTP request
//import HttpProtocols._
//import MediaTypes._
Authorization authorization = Authorization.basic("user", "pass");
HttpRequest complexRequest =
HttpRequest.PUT("/user")
.withEntity(HttpEntities.create(MediaTypes.TEXT_PLAIN.toContentType(), "abc"))
.addHeader(authorization)
.withProtocol(HttpProtocols.HTTP_1_0);
//#construct-request
}
@Test
public void testConstructResponse() {
//#construct-response
// simple OK response without data created using the integer status code
HttpResponse ok = HttpResponse.create().withStatus(200);
// 404 response created using the named StatusCode constant
HttpResponse notFound = HttpResponse.create().withStatus(StatusCodes.NOT_FOUND);
// 404 response with a body explaining the error
HttpResponse notFoundCustom =
HttpResponse.create()
.withStatus(404)
.withEntity("Unfortunately, the resource couldn't be found.");
// A redirecting response containing an extra header
Location locationHeader = Location.create("http://example.com/other");
HttpResponse redirectResponse =
HttpResponse.create()
.withStatus(StatusCodes.FOUND)
.addHeader(locationHeader);
//#construct-response
}
@Test
public void testDealWithHeaders() {
//#headers
// create a ``Location`` header
Location locationHeader = Location.create("http://example.com/other");
// create an ``Authorization`` header with HTTP Basic authentication data
Authorization authorization = Authorization.basic("user", "pass");
//#headers
}
//#headers
// a method that extracts basic HTTP credentials from a request
private Option<BasicHttpCredentials> getCredentialsOfRequest(HttpRequest request) {
Option<Authorization> auth = request.getHeader(Authorization.class);
if (auth.isDefined() && auth.get().credentials() instanceof BasicHttpCredentials)
return Option.some((BasicHttpCredentials) auth.get().credentials());
else
return Option.none();
}
//#headers
}

View file

@ -0,0 +1,8 @@
.. _ConnectionLevelApi-java:
Connection-Level Client-Side API
================================
TODO
For the time being, :ref:`see the Scala chapter on the same topic <ConnectionLevelApi>`.

View file

@ -0,0 +1,8 @@
.. _HostLevelApi-java:
Host-Level Client-Side API
==========================
TODO
For the time being, :ref:`see the Scala chapter on the same topic <HostLevelApi>`.

View file

@ -0,0 +1,8 @@
.. _clientSideHTTPS-java:
Client-Side HTTPS Support
=========================
TODO
For the time being, :ref:`see the Scala chapter on the same topic <clientSideHTTPS>`.

View file

@ -0,0 +1,15 @@
.. _http-client-side-java:
Consuming HTTP-based Services (Client-Side)
===========================================
...
.. toctree::
:maxdepth: 2
connection-level
host-level
request-level
https-support
websocket-support

View file

@ -0,0 +1,8 @@
.. _RequestLevelApi-java:
Request-Level Client-Side API
=============================
TODO
For the time being, :ref:`see the Scala chapter on the same topic <RequestLevelApi>`.

View file

@ -0,0 +1,8 @@
.. _client-side-websocket-support-java:
Client-Side WebSocket Support
=============================
Not yet implemented see 17275_.
.. _17275: https://github.com/akka/akka/issues/17275

View file

@ -0,0 +1,28 @@
.. _akka-http-configuration-java:
Configuration
=============
Just like any other Akka module Akka HTTP is configured via `Typesafe Config`_.
Usually this means that you provide an ``application.conf`` which contains all the application-specific settings that
differ from the default ones provided by the reference configuration files from the individual Akka modules.
These are the relevant default configuration values for the Akka HTTP modules.
akka-http-core
~~~~~~~~~~~~~~
.. literalinclude:: ../../../../akka-http-core/src/main/resources/reference.conf
:language: none
akka-http
~~~~~~~~~
.. literalinclude:: ../../../../akka-http/src/main/resources/reference.conf
:language: none
The other Akka HTTP modules do not offer any configuration via `Typesafe Config`_.
.. _Typesafe Config: https://github.com/typesafehub/config

View file

@ -0,0 +1,233 @@
.. _http-model-java:
HTTP Model
==========
Akka HTTP model contains a deeply structured, fully immutable, case-class based model of all the major HTTP data
structures, like HTTP requests, responses and common headers.
It lives in the *akka-http-core* module and forms the basis for most of Akka HTTP's APIs.
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
:include: import-model
This brings all of the most relevant types in scope, mainly:
- ``HttpRequest`` and ``HttpResponse``, the central message model
- ``headers``, the package containing all the predefined HTTP header models and supporting types
- Supporting types like ``Uri``, ``HttpMethods``, ``MediaTypes``, ``StatusCodes``, etc.
A common pattern is that the model of a certain entity is represented by an immutable type (class or trait),
while the actual instances of the entity defined by the HTTP spec live in an accompanying object carrying the name of
the type plus a trailing plural 's'.
For example:
- Defined ``HttpMethod`` instances are defined as static fields of the ``HttpMethods`` class.
- Defined ``HttpCharset`` instances are defined as static fields of the ``HttpCharsets`` class.
- Defined ``HttpEncoding`` instances are defined as static fields of the ``HttpEncodings`` class.
- Defined ``HttpProtocol`` instances are defined as static fields of the ``HttpProtocols`` class.
- Defined ``MediaType`` instances are defined as static fields of the ``MediaTypes`` class.
- Defined ``StatusCode`` instances are defined as static fields of the ``StatusCodes`` class.
HttpRequest
-----------
``HttpRequest`` and ``HttpResponse`` are the basic immutable classes representing HTTP messages.
An ``HttpRequest`` consists of
- a method (GET, POST, etc.)
- a URI
- a seq of headers
- an entity (body data)
- a protocol
Here are some examples how to construct an ``HttpRequest``:
.. includecode:: ../code/docs/http/javadsl/ModelSpec.java
:include: construct-request
In its basic form ``HttpRequest.create`` creates an empty default GET request without headers which can then be
transformed using one of the ``withX`` methods, ``addHeader``, or ``addHeaders``. Each of those will create a
new immutable instance, so instances can be shared freely. There exist some overloads for ``HttpRequest.create`` that
simplify creating requests for common cases. Also, to aid readability, there are predefined alternatives for ``create``
named after HTTP methods to create a request with a given method and uri directly.
HttpResponse
------------
An ``HttpResponse`` consists of
- a status code
- a list of headers
- an entity (body data)
- a protocol
Here are some examples how to construct an ``HttpResponse``:
.. includecode:: ../code/docs/http/javadsl/ModelSpec.java
:include: construct-response
In addition to the simple ``HttpEntities.create`` methods which create an entity from a fixed ``String`` or ``ByteString``
as shown here the Akka HTTP model defines a number of subclasses of ``HttpEntity`` which allow body data to be specified as a
stream of bytes. All of these types can be created using the method on ``HttpEntites``.
.. _HttpEntity-java:
HttpEntity
----------
An ``HttpEntity`` carries the data bytes of a message together with its Content-Type and, if known, its Content-Length.
In Akka HTTP there are five different kinds of entities which model the various ways that message content can be
received or sent:
HttpEntityStrict
The simplest entity, which is used when all the entity are already available in memory.
It wraps a plain ``ByteString`` and represents a standard, unchunked entity with a known ``Content-Length``.
HttpEntityDefault
The general, unchunked HTTP/1.1 message entity.
It has a known length and presents its data as a ``Source[ByteString]`` which can be only materialized once.
It is an error if the provided source doesn't produce exactly as many bytes as specified.
The distinction of ``HttpEntityStrict`` and ``HttpEntityDefault`` is an API-only one. One the wire,
both kinds of entities look the same.
HttpEntityChunked
The model for HTTP/1.1 `chunked content`__ (i.e. sent with ``Transfer-Encoding: chunked``).
The content length is unknown and the individual chunks are presented as a ``Source[ChunkStreamPart]``.
A ``ChunkStreamPart`` is either a non-empty chunk or the empty last chunk containing optional trailer headers.
The stream consists of zero or more non-empty chunks parts and can be terminated by an optional last chunk.
HttpEntityCloseDelimited
An unchunked entity of unknown length that is implicitly delimited by closing the connection (``Connection: close``).
Content data is presented as a ``Source[ByteString]``.
Since the connection must be closed after sending an entity of this type it can only be used on the server-side for
sending a response.
Also, the main purpose of ``CloseDelimited`` entities is compatibility with HTTP/1.0 peers, which do not support
chunked transfer encoding. If you are building a new application and are not constrained by legacy requirements you
shouldn't rely on ``CloseDelimited`` entities, since implicit terminate-by-connection-close is not a robust way of
signaling response end, especially in the presence of proxies. Additionally this type of entity prevents connection
reuse which can seriously degrade performance. Use ``HttpEntityChunked`` instead!
HttpEntityIndefiniteLength
A streaming entity of unspecified length for use in a ``Multipart.BodyPart``.
__ http://tools.ietf.org/html/rfc7230#section-4.1
Entity types ``HttpEntityStrict``, ``HttpEntityDefault``, and ``HttpEntityChunked`` are a subtype of ``RequestEntity``
which allows to use them for requests and responses. In contrast, ``HttpEntityCloseDelimited`` can only be used for responses.
Streaming entity types (i.e. all but ``HttpEntityStrict``) cannot be shared or serialized. To create a strict, sharable copy of an
entity or message use ``HttpEntity.toStrict`` or ``HttpMessage.toStrict`` which returns a ``Future`` of the object with
the body data collected into a ``ByteString``.
The class ``HttpEntities`` contains static methods to create entities from common types easily.
You can use the ``isX` methods of ``HttpEntity`` to find out of which subclass an entity is if you want to provide
special handling for each of the subtypes. However, in many cases a recipient of an ``HttpEntity`` doesn't care about
of which subtype an entity is (and how data is transported exactly on the HTTP layer). Therefore, a general
``HttpEntity::getDataBytes: Source<ByteString, ?>`` is provided which allows access to the data of an entity regardless
of its concrete subtype.
.. note::
When to use which subtype?
- Use ``HttpEntityStrict`` if the amount of data is "small" and already available in memory (e.g. as a ``String`` or ``ByteString``)
- Use ``HttpEntityDefault`` if the data is generated by a streaming data source and the size of the data is known
- Use ``HttpEntityChunked`` for an entity of unknown length
- Use ``HttpEntityCloseDelimited`` for a response as a legacy alternative to ``HttpEntityChunked`` if the client
doesn't support chunked transfer encoding. Otherwise use ``HttpEntityChunked``!
- In a ``Multipart.Bodypart`` use ``HttpEntityIndefiniteLength`` for content of unknown length.
.. caution::
When you receive a non-strict message from a connection then additional data is only read from the network when you
request it by consuming the entity data stream. This means that, if you *don't* consume the entity stream then the
connection will effectively be stalled. In particular, no subsequent message (request or response) will be read from
the connection as the entity of the current message "blocks" the stream.
Therefore you must make sure that you always consume the entity data, even in the case that you are not actually
interested in it!
Header Model
------------
Akka HTTP contains a rich model of the most common HTTP headers. Parsing and rendering is done automatically so that
applications don't need to care for the actual syntax of headers. Headers not modelled explicitly are represented
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
:include: headers
HTTP Headers
------------
When the Akka HTTP server receives an HTTP request it tries to parse all its headers into their respective
model classes. Independently of whether this succeeds or not, the HTTP layer will
always pass on all received headers to the application. Unknown headers as well as ones with invalid syntax (according
to the header parser) will be made available as ``RawHeader`` instances. For the ones exhibiting parsing errors a
warning message is logged depending on the value of the ``illegal-header-warnings`` config setting.
Some headers have special status in HTTP and are therefore treated differently from "regular" headers:
Content-Type
The Content-Type of an HTTP message is modeled as the ``contentType`` field of the ``HttpEntity``.
The ``Content-Type`` header therefore doesn't appear in the ``headers`` sequence of a message.
Also, a ``Content-Type`` header instance that is explicitly added to the ``headers`` of a request or response will
not be rendered onto the wire and trigger a warning being logged instead!
Transfer-Encoding
Messages with ``Transfer-Encoding: chunked`` are represented as a ``HttpEntityChunked`` entity.
As such chunked messages that do not have another deeper nested transfer encoding will not have a ``Transfer-Encoding``
header in their ``headers`` list.
Similarly, a ``Transfer-Encoding`` header instance that is explicitly added to the ``headers`` of a request or
response will not be rendered onto the wire and trigger a warning being logged instead!
Content-Length
The content length of a message is modelled via its :ref:`HttpEntity-java`. As such no ``Content-Length`` header will ever
be part of a message's ``header`` sequence.
Similarly, a ``Content-Length`` header instance that is explicitly added to the ``headers`` of a request or
response will not be rendered onto the wire and trigger a warning being logged instead!
Server
A ``Server`` header is usually added automatically to any response and its value can be configured via the
``akka.http.server.server-header`` setting. Additionally an application can override the configured header with a
custom one by adding it to the response's ``header`` sequence.
User-Agent
A ``User-Agent`` header is usually added automatically to any request and its value can be configured via the
``akka.http.client.user-agent-header`` setting. Additionally an application can override the configured header with a
custom one by adding it to the request's ``header`` sequence.
Date
The ``Date`` response header is added automatically but can be overridden by supplying it manually.
Connection
On the server-side Akka HTTP watches for explicitly added ``Connection: close`` response headers and as such honors
the potential wish of the application to close the connection after the respective response has been sent out.
The actual logic for determining whether to close the connection is quite involved. It takes into account the
request's method, protocol and potential ``Connection`` header as well as the response's protocol, entity and
potential ``Connection`` header. See `this test`__ for a full table of what happens when.
__ @github@/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/ResponseRendererSpec.scala#L422
Parsing / Rendering
-------------------
Parsing and rendering of HTTP data structures is heavily optimized and for most types there's currently no public API
provided to parse (or render to) Strings or byte arrays.

View file

@ -3,4 +3,13 @@
Akka HTTP
=========
...
.. toctree::
:maxdepth: 2
introduction
configuration
http-model
server-side/low-level-server-side-api
server-side/websocket-support
routing-dsl/index
client-side/index

View file

@ -0,0 +1,28 @@
Introduction
============
The Akka HTTP modules implement a full server- and client-side HTTP stack on top of *akka-actor* and *akka-stream*. It's
not a web-framework but rather a more general toolkit for providing and consuming HTTP-based services. While interaction
with a browser is of course also in scope it is not the primary focus of Akka HTTP.
Akka HTTP follows a rather open design and many times offers several different API levels for "doing the same thing".
You get to pick the API level of abstraction that is most suitable for your application.
This means that, if you have trouble achieving something using a high-level API, there's a good chance that you can get
it done with a low-level API, which offers more flexibility but might require you to write more application code.
Akka HTTP is structured into several modules:
akka-http-core
A complete, mostly low-level, server- and client-side implementation of HTTP (incl. WebSockets)
akka-http
Higher-level functionality, like (un)marshalling, (de)compression as well as a powerful DSL
for defining HTTP-based APIs on the server-side
akka-http-testkit
A test harness and set of utilities for verifying server-side service implementations
akka-http-jackson
Predefined glue-code for (de)serializing custom types from/to JSON with jackson_
.. _jackson: https://github.com/FasterXML/jackson

View file

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

View file

@ -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<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<?>``
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

View file

@ -0,0 +1,17 @@
.. _http-high-level-server-side-api-java:
High-level Server-Side API
==========================
...
.. toctree::
:maxdepth: 1
overview
routes
directives/index
request-vals/index
handlers
path-matchers
marshalling

View file

@ -0,0 +1,6 @@
.. _marshalling-java:
Marshalling & Unmarshalling
===========================
TODO

View file

@ -0,0 +1,71 @@
.. _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`.
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.
Read more about :ref:`marshalling-java`.
.. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself

View file

@ -0,0 +1,6 @@
.. _pathmatcher-dsl-java:
The PathMatcher DSL
===================
TODO

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.

View file

@ -0,0 +1,156 @@
.. _http-low-level-server-side-api-java:
Low-Level Server-Side API
=========================
Apart from the :ref:`HTTP Client <http-client-side-java>` Akka HTTP also provides an embedded,
`Reactive-Streams`_-based, fully asynchronous HTTP/1.1 server implemented on top of :ref:`Akka Stream <streams-java>`.
It sports the following features:
- Full support for `HTTP persistent connections`_
- Full support for `HTTP pipelining`_
- Full support for asynchronous HTTP streaming including "chunked" transfer encoding accessible through an idiomatic API
- Optional SSL/TLS encryption
- Websocket support
.. _HTTP persistent connections: http://en.wikipedia.org/wiki/HTTP_persistent_connection
.. _HTTP pipelining: http://en.wikipedia.org/wiki/HTTP_pipelining
.. _Reactive-Streams: http://www.reactive-streams.org/
The server-side components of Akka HTTP are split into two layers:
1. The basic low-level server implementation in the ``akka-http-core`` module
2. Higher-level functionality in the ``akka-http`` module
The low-level server (1) is scoped with a clear focus on the essential functionality of an HTTP/1.1 server:
- Connection management
- Parsing and rendering of messages and headers
- Timeout management (for requests and connections)
- Response ordering (for transparent pipelining support)
All non-core features of typical HTTP servers (like request routing, file serving, compression, etc.) are left to
the higher layers, they are not implemented by the ``akka-http-core``-level server itself.
Apart from general focus this design keeps the server core small and light-weight as well as easy to understand and
maintain.
Depending on your needs you can either use the low-level API directly or rely on the high-level
:ref:`Routing DSL <http-high-level-server-side-api-java>` which can make the definition of more complex service logic much
easier.
Streams and HTTP
----------------
The Akka HTTP server is implemented on top of :ref:`Akka Stream <streams-java>` and makes heavy use of it - in its
implementation as well as on all levels of its API.
On the connection level Akka HTTP offers basically the same kind of interface as :ref:`Akka Stream IO <stream-io-java>`:
A socket binding is represented as a stream of incoming connections. The application pulls connections from this stream
source and, for each of them, provides a ``Flow<HttpRequest, HttpResponse, ?>`` to "translate" requests into responses.
Apart from regarding a socket bound on the server-side as a ``Source<IncomingConnection>`` and each connection as a
``Source<HttpRequest>`` with a ``Sink<HttpResponse>`` the stream abstraction is also present inside a single HTTP
message: The entities of HTTP requests and responses are generally modeled as a ``Source<ByteString>``. See also
the :ref:`http-model-java` for more information on how HTTP messages are represented in Akka HTTP.
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/HttpServerExampleSpec.java
:include: binding-example
Arguments to the ``Http().bind`` method specify the interface and port to bind to and register interest in handling
incoming HTTP connections. Additionally, the method also allows for the definition of socket options as well as a larger
number of settings for configuring the server according to your needs.
The result of the ``bind`` method is a ``Source<Http.IncomingConnection>`` which must be drained by the application in
order to accept incoming connections.
The actual binding is not performed before this source is materialized as part of a processing pipeline. In
case the bind fails (e.g. because the port is already busy) the materialized stream will immediately be terminated with
a respective exception.
The binding is released (i.e. the underlying socket unbound) when the subscriber of the incoming
connection source has cancelled its subscription. Alternatively one can use the ``unbind()`` method of the
``Http.ServerBinding`` instance that is created as part of the connection source's materialization process.
The ``Http.ServerBinding`` also provides a way to get a hold of the actual local address of the bound socket, which is
useful for example when binding to port zero (and thus letting the OS pick an available port).
.. _akka.http.javadsl.Http: @github@/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala
.. _http-low-level-server-side-example-java:
Request-Response Cycle
----------------------
When a new connection has been accepted it will be published as an ``Http.IncomingConnection`` which consists
of the remote address and methods to provide a ``Flow<HttpRequest, HttpResponse, ?>`` to handle requests coming in over
this connection.
Requests are handled by calling one of the ``handleWithXXX`` methods with a handler, which can either be
- a ``Flow<HttpRequest, HttpResponse, ?>`` for ``handleWith``,
- a function ``Function<HttpRequest, HttpResponse>`` for ``handleWithSyncHandler``,
- a function ``Function<HttpRequest, Future<HttpResponse>>`` for ``handleWithAsyncHandler``.
Here is a complete example:
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleSpec.java
:include: full-server-example
In this example, a request is handled by transforming the request stream with a function ``Function<HttpRequest, HttpResponse>``
using ``handleWithSyncHandler`` (or equivalently, Akka Stream's ``map`` operator). Depending on the use case many
other ways of providing a request handler are conceivable using Akka Stream's combinators.
If the application provides a ``Flow`` it is also the responsibility of the application to generate exactly one response
for every request and that the ordering of responses matches the ordering of the associated requests (which is relevant
if HTTP pipelining is enabled where processing of multiple incoming requests may overlap). When relying on
``handleWithSyncHandler`` or ``handleWithAsyncHandler``, or the ``map`` or ``mapAsync`` stream operators, this
requirement will be automatically fulfilled.
See :ref:`routing-java` for a more convenient high-level DSL to create request handlers.
Streaming Request/Response Entities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Streaming of HTTP message entities is supported through subclasses of ``HttpEntity``. The application needs to be able
to deal with streamed entities when receiving a request as well as, in many cases, when constructing responses.
See :ref:`HttpEntity-java` for a description of the alternatives.
Closing a connection
~~~~~~~~~~~~~~~~~~~~
The HTTP connection will be closed when the handling ``Flow`` cancels its upstream subscription or the peer closes the
connection. An often times more convenient alternative is to explicitly add a ``Connection: close`` header to an
``HttpResponse``. This response will then be the last one on the connection and the server will actively close the
connection when it has been sent out.
.. _serverSideHTTPS-java:
Server-Side HTTPS Support
-------------------------
Akka HTTP supports TLS encryption on the server-side as well as on the :ref:`client-side <clientSideHTTPS-java>`.
The central vehicle for configuring encryption is the ``HttpsContext``, which can be created using ``HttpsContext.create``
which is defined like this:
.. includecode:: /../../akka-http-core/src/main/java/akka/http/javadsl/HttpsContext.java
:include: http-context-creation
On the server-side the ``bind``, and ``bindAndHandleXXX`` methods of the `akka.http.javadsl.Http`_ extension define an
optional ``httpsContext`` parameter, which can receive the HTTPS configuration in the form of an ``HttpsContext``
instance.
If defined encryption is enabled on all accepted connections. Otherwise it is disabled (which is the default).
Stand-Alone HTTP Layer Usage
----------------------------
// TODO

View file

@ -0,0 +1,8 @@
.. _server-side-websocket-support-java:
Server-Side WebSocket Support
=============================
TODO
For the time being, :ref:`see the Scala chapter on the same topic <server-side-websocket-support-scala>`.

View file

@ -334,7 +334,7 @@ In essence, the above guarantees are similar to what :class:`Actor`s provide, if
stage as state of an actor, and the callbacks as the ``receive`` block of the actor.
.. warning::
It is **not safe** to access the state of any custom stage outside of the callbacks that it provides, just like it
It is **not safe** to access the state of any custom stage outside of the callbacks that it provides, just like it
is unsafe to access the state of an actor from the outside. This means that Future callbacks should **not close over**
internal state of custom stages because such access can be concurrent with the provided callbacks, leading to undefined
behavior.

View file

@ -119,6 +119,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
}
}
// `route` will be implicitly converted to `Flow` using `RouteResult.route2HandlerFlow`
Http().bindAndHandle(route, "localhost", 8080)
}

View file

@ -1,4 +1,8 @@
.. _client-side-websocket-support:
Client-Side WebSocket Support
=============================
TODO
Not yet implemented see 17275_.
.. _17275: https://github.com/akka/akka/issues/17275

View file

@ -72,8 +72,8 @@ Here are some examples how to construct an ``HttpResponse``:
.. includecode:: ../../code/docs/http/scaladsl/ModelSpec.scala
:include: construct-response
In addition to the simple ``HttpEntity`` constructors create an entity from a fixed ``String`` or ``ByteString`` shown
as here the Akka HTTP model defines a number of subclasses of ``HttpEntity`` which allow body data to be specified as a
In addition to the simple ``HttpEntity`` constructors which create an entity from a fixed ``String`` or ``ByteString``
as shown here the Akka HTTP model defines a number of subclasses of ``HttpEntity`` which allow body data to be specified as a
stream of bytes.
@ -93,9 +93,9 @@ HttpEntity.Strict
HttpEntity.Default
The general, unchunked HTTP/1.1 message entity.
It has a known length and presents its data as a ``Source[ByteString]`` which can only materialized once.
It has a known length and presents its data as a ``Source[ByteString]`` which can be only materialized once.
It is an error if the provided source doesn't produce exactly as many bytes as specified.
On the wire, a ``Strict`` entity and a ``Default`` entity cannot be distinguished.
The distinction of ``Strict`` and ``Default`` is an API-only one. One the wire, both kinds of entities look the same.
HttpEntity.Chunked

View file

@ -16,8 +16,8 @@ akka-http-core
:language: none
akka-http-core-scala
~~~~~~~~~~~~~~~~~~~~
akka-http
~~~~~~~~~
.. literalinclude:: ../../../../akka-http/src/main/resources/reference.conf
:language: none

View file

@ -8,7 +8,7 @@ with a browser is of course also in scope it is not the primary focus of Akka HT
Akka HTTP follows a rather open design and many times offers several different API levels for "doing the same thing".
You get to pick the API level of abstraction that is most suitable for your application.
This means that, if you have trouble achieving something using a high-level API, there's a good chance that you can get
it done with a low-level API, which offers more flexibility but might require you do write more application code.
it done with a low-level API, which offers more flexibility but might require you to write more application code.
Akka HTTP is structured into several modules:

View file

@ -12,6 +12,7 @@ It sports the following features:
- Full support for `HTTP pipelining`_
- Full support for asynchronous HTTP streaming including "chunked" transfer encoding accessible through an idiomatic API
- Optional SSL/TLS encryption
- Websocket support
.. _HTTP persistent connections: http://en.wikipedia.org/wiki/HTTP_persistent_connection
.. _HTTP pipelining: http://en.wikipedia.org/wiki/HTTP_pipelining
@ -26,7 +27,7 @@ The server-side components of Akka HTTP are split into two layers:
The low-level server (1) is scoped with a clear focus on the essential functionality of an HTTP/1.1 server:
- Connection management
- Parsing messages and headers
- Parsing and rendering of messages and headers
- Timeout management (for requests and connections)
- Response ordering (for transparent pipelining support)

View file

@ -15,7 +15,9 @@ 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`) in a concise and readable way. Directives are assembled into a so called
*route structure* which, at its top-level, forms a handler ``Flow`` (or, alternatively, an async handler function) that
can be directly supplied to a ``bind`` call.
can be directly supplied to a ``bind`` call. The conversion from ``Route`` to flow can either be invoked explicitly
using ``Route.handlerFlow`` or, otherwise, the conversion is also provided implicitly by
``RouteResult.route2HandlerFlow`` [1]_.
For example, the service definition from above, written using the routing DSL, would look like this:
@ -37,5 +39,12 @@ regard.
For learning how to work with the Routing DSL you should first understand the concept of :ref:`Routes`.
.. [1] To be picked up automatically, the implicit conversion needs to be provided in the companion object of the source
type. However, as ``Route`` is just a type alias for ``RequestContext => Future[RouteResult]``, there's no
companion object for ``Route``. Fortunately, the `implicit scope`_ for finding an implicit conversion also
includes all types that are "associated with any part" of the source type which in this case means that the
implicit conversion will also be picked up from ``RouteResult.route2HandlerFlow`` automatically.
.. _Unfiltered: http://unfiltered.databinder.net/
.. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
.. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
.. _implicit scope: http://www.scala-lang.org/files/archive/spec/2.11/07-implicits.html#implicit-parameters

View file

@ -1,3 +1,5 @@
.. _server-side-websocket-support-scala:
Server-Side WebSocket Support
=============================