!htp #18919 #19519 New JavaDSL for Akka HTTP (#20518)

* !htt #18919 #19519 Align Java HTTP server DSL with Scala

This commits replaces the Java HTTP server DSL with a Java-8 centric one
which exposes all scala DSL concepts to be usable from Java, including
custom directives, (un)marshallers, rejections, headers, and type safety
for path and query parameters.

* Add RequestContext and RouteResult to Java DSL
fix websockets
WIP bring java docs up to date.
This applies some updates to the root-level documentation

* [htp] Fix java documentation to correctly mention timeouts

Timeouts are configured the same in Java and Scala. Hence, linking to the
scala docs for timeouts from Java.

* =htc fix optionalHeaderValueByType in Java

* =htt #20200 fix java testkit always using NoLogging instead logger

* +htt actually run new javadsl tests, allow overriding config

* =htt improve javadsl test infra with more details when fails

* =htt fix bug in wrong path matcher exposed

* +htp add missing remaining path matcher

* =htp Java DSL cookie tests fixed

* =htt Java DSL ParameterDirectivesTest fixed

Protect the tweets from scalariform

Incorrect response expectations in cache condition directives spec fixed

* =htt Path directives for Java DSL

* +!htt PathMatchers rewritten, made uniform and tests passing

* Bugfix in java reject and a little test-boyscouting

* Revert "Incorrect response expectations in cache condition directives spec fixed"

This reverts commit cd50e89d45db010309f8249b090ea654ebb11c7a.

* +htc HttpAPIsTest is compile time only, not for running
Also, moved from the client package since not strictly a client test.

SecurityDirectives passing

Two faulty tests and two actual bugs.

Fix for cache condition spec not working

* Not sending in Unit instad of the implicit magnet in the test
* HeaderMagnet now works as expected
* Java API added for - and + on DateTime

PetStore example and test fixed

* Annotations to make marshalling work without default constructor
* Made model class immutable

Incorrect tests fixed

Some scaladoc boyscouting as bonus

* =htt RequestValTest sprinkled out across multiple directive tests

Client ip extraction test with incorrect header name fixed.

* =htt Incorrect CodingDirectivesTest fixed.

* =htt Bugfix for Java Unmarshaller.firstOf and fixes to JavaRouteTest

* =htt MarshallerTest fixed

* Missing seal signature added to JavaDSL
* More consistent (with Scala) test kit setup for Java
* missing Javadocs added
* Thread.sleep in default exception handler removed

* =htt copy directive docs, prepare for finishing it up

* +htt SecurityDirectives.authorize variants and test coverage added

* +htt Custom headers in Java DSL

* =htt WIP on java docs

* +htp add missing parameterOrDefault directive
Fixed a lot of doc warnings

* =htc intense progress on javadsl docs

* =htc #20470 Link to issue about docs and fix compile error
compile, migration guide
don't mima check http-experimental

* =htt Java DSL doc warnings fixed.
Only `Could not lex literal_block` ones left now

* =htc fix mima settings

* =doc fix MethodDirectives doc test with custom method

* =htc fix coding directives spec after bad merge

* =htc fix concat being corresponding to route() in javadsl

* =htt Disable consistency check for route/concat as it fails only on ci server

* !htt Minor fixes to PathMatchers
This commit is contained in:
Johan Andrén 2016-05-16 10:38:40 +02:00 committed by Konrad Malawski
parent 094c8974ed
commit 29029be31d
381 changed files with 12616 additions and 6630 deletions

View file

@ -4,27 +4,28 @@
package docs.http.javadsl.server;
import org.junit.Test;
import akka.http.javadsl.model.FormData;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.server.values.FormField;
import akka.http.javadsl.server.values.FormFields;
import akka.http.javadsl.server.StringUnmarshallers;
import akka.http.javadsl.server.StringUnmarshaller;
import akka.http.javadsl.server.Unmarshaller;
import akka.http.javadsl.testkit.JUnitRouteTest;
import akka.japi.Pair;
import org.junit.Test;
public class FormFieldRequestValsExampleTest extends JUnitRouteTest {
@Test
public void testFormFieldVals() {
//#simple
FormField<String> name = FormFields.stringValue("name");
FormField<Integer> age = FormFields.intValue("age");
final Route route =
route(
handleWith2(name, age, (ctx, n, a) ->
ctx.complete(String.format("Name: %s, age: %d", n, a))
formField("name", n ->
formField(StringUnmarshallers.INTEGER, "age", a ->
complete(String.format("Name: %s, age: %d", n, a))
)
);
@ -44,13 +45,11 @@ public class FormFieldRequestValsExampleTest extends JUnitRouteTest {
@Test
public void testFormFieldValsUnmarshaling() {
//#custom-unmarshal
FormField<SampleId> sampleId = FormFields.fromString("id", SampleId.class, s -> new SampleId(Integer.valueOf(s)));
Unmarshaller<String, SampleId> SAMPLE_ID = StringUnmarshaller.sync(s -> new SampleId(Integer.valueOf(s)));
final Route route =
route(
handleWith1(sampleId, (ctx, sid) ->
ctx.complete(String.format("SampleId: %s", sid.id))
)
formField(SAMPLE_ID, "id", sid ->
complete(String.format("SampleId: %s", sid.id))
);
// tests:

View file

@ -4,28 +4,23 @@
package docs.http.javadsl.server;
import org.junit.Test;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.headers.Host;
import akka.http.javadsl.model.headers.RawHeader;
import akka.http.javadsl.server.RequestVal;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.server.values.Headers;
import akka.http.javadsl.testkit.JUnitRouteTest;
import org.junit.Test;
public class HeaderRequestValsExampleTest extends JUnitRouteTest {
@Test
public void testHeaderVals() {
//#by-class
// extract the entire header instance:
RequestVal<Host> host = Headers.byClass(Host.class).instance();
final Route route =
route(
handleWith1(host, (ctx, h) ->
ctx.complete(String.format("Host header was: %s", h.host()))
)
extractHost(host ->
complete(String.format("Host header was: %s", host))
);
// tests:
@ -41,14 +36,11 @@ public class HeaderRequestValsExampleTest extends JUnitRouteTest {
@Test
public void testHeaderByName() {
//#by-name
// extract the `value` of the header:
final RequestVal<String> XFishName = Headers.byName("X-Fish-Name").value();
final Route route =
route(
handleWith1(XFishName, (ctx, xFishName) ->
ctx.complete(String.format("The `X-Fish-Name` header's value was: %s", xFishName))
)
// extract the `value` of the header:
headerValueByName("X-Fish-Name", xFishName ->
complete(String.format("The `X-Fish-Name` header's value was: %s", xFishName))
);
// tests:

View file

@ -5,28 +5,41 @@
package docs.http.javadsl.server;
//#binding-failure-high-level-example
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.http.scaladsl.Http;
import akka.http.javadsl.ConnectHttp;
import akka.http.javadsl.ServerBinding;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.Http;
import akka.stream.ActorMaterializer;
import akka.stream.javadsl.Flow;
import java.io.IOException;
import java.util.concurrent.CompletionStage;
public class HighLevelServerBindFailureExample {
public static void main(String[] args) throws IOException {
// boot up server using the route as defined below
final ActorSystem system = ActorSystem.create();
public static void main(String[] args) throws IOException {
// boot up server using the route as defined below
final ActorSystem system = ActorSystem.create();
final ActorMaterializer materializer = ActorMaterializer.create(system);
// HttpApp.bindRoute expects a route being provided by HttpApp.createRoute
CompletionStage<Http.ServerBinding> bindingFuture =
new HighLevelServerExample().bindRoute("localhost", 8080, system);
// HttpApp.bindRoute expects a route being provided by HttpApp.createRoute
final HighLevelServerExample app = new HighLevelServerExample();
final Route route = app.createRoute();
bindingFuture.exceptionally(failure -> {
System.err.println("Something very bad happened! " + failure.getMessage());
system.terminate();
return null;
});
final Flow<HttpRequest, HttpResponse, NotUsed> handler = route.flow(system, materializer);
final CompletionStage<ServerBinding> binding = Http.get(system).bindAndHandle(handler, ConnectHttp.toHost("127.0.0.1", 8080), materializer);
system.terminate();
}
binding.exceptionally(failure -> {
System.err.println("Something very bad happened! " + failure.getMessage());
system.terminate();
return null;
});
system.terminate();
}
}
//#binding-failure-high-level-example

View file

@ -5,65 +5,73 @@
package docs.http.javadsl.server;
//#high-level-server-example
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.http.javadsl.ConnectHttp;
import akka.http.javadsl.Http;
import akka.http.javadsl.ServerBinding;
import akka.http.javadsl.model.ContentTypes;
import akka.http.javadsl.model.MediaTypes;
import akka.http.javadsl.server.*;
import akka.http.javadsl.server.values.Parameters;
import akka.http.javadsl.model.HttpEntities;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.server.AllDirectives;
import akka.http.javadsl.server.Route;
import akka.stream.ActorMaterializer;
import akka.stream.javadsl.Flow;
import java.io.IOException;
import java.util.concurrent.CompletionStage;
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();
public class HighLevelServerExample extends AllDirectives {
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.terminate();
}
// HttpApp.bindRoute expects a route being provided by HttpApp.createRoute
final HighLevelServerExample app = new HighLevelServerExample();
// 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");
final Http http = Http.get(system);
final ActorMaterializer materializer = ActorMaterializer.create(system);
@Override
public Route createRoute() {
// This handler generates responses to `/hello?name=XXX` requests
Route helloRoute =
handleWith1(name,
// in Java 8 the following becomes simply
// (ctx, name) -> ctx.complete("Hello " + name + "!")
new Handler1<String>() {
@Override
public RouteResult apply(RequestContext ctx, String name) {
return ctx.complete("Hello " + name + "!");
}
});
final Flow<HttpRequest, HttpResponse, NotUsed> routeFlow = app.createRoute().flow(system, materializer);
final CompletionStage<ServerBinding> binding = http.bindAndHandle(routeFlow, ConnectHttp.toHost("localhost", 8080), materializer);
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(ContentTypes.TEXT_HTML_UTF8,
"<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
)
)
);
}
System.out.println("Type RETURN to exit");
System.in.read();
binding
.thenCompose(ServerBinding::unbind)
.thenAccept(unbound -> system.terminate());
}
public Route createRoute() {
// This handler generates responses to `/hello?name=XXX` requests
Route helloRoute =
parameterOptional("name", optName -> {
String name = optName.orElse("Mister X");
return complete("Hello " + name + "!");
});
return
// here the complete behavior for this server is defined
// only handle GET requests
get(() -> route(
// matches the empty path
pathSingleSlash(() ->
// return a constant string with a certain content type
complete(HttpEntities.create(ContentTypes.TEXT_HTML_UTF8, "<html><body>Hello world!</body></html>"))
),
path("ping", () ->
// return a simple `text/plain` response
complete("PONG!")
),
path("hello", () ->
// uses the route defined above
helloRoute
)
));
}
}
//#high-level-server-example
//#high-level-server-example

View file

@ -4,59 +4,35 @@
package docs.http.javadsl.server;
import java.util.Optional;
import org.junit.Test;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.headers.Host;
import akka.http.javadsl.server.Handler1;
import akka.http.javadsl.server.RequestContext;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.server.RouteResult;
import akka.http.javadsl.server.values.BasicCredentials;
import akka.http.javadsl.server.values.HttpBasicAuthenticator;
import akka.http.javadsl.testkit.JUnitRouteTest;
import akka.http.scaladsl.model.headers.Authorization;
import java.util.Optional;
import java.util.concurrent.CompletionStage;
import org.junit.Test;
import scala.Option;
import scala.concurrent.Future;
public class HttpBasicAuthenticatorExample extends JUnitRouteTest {
private final String hardcodedPassword = "correcthorsebatterystaple";
private Optional<String> authenticate(Optional<ProvidedCredentials> creds) {
// this is where your actual authentication logic would go
return creds
.filter(c -> c.verify(hardcodedPassword)) // Only allow users that provide the right password
.map(c -> c.identifier()); // Provide the username down to the inner route
}
@Test
public void testBasicAuthenticator() {
//#basic-authenticator-java
final HttpBasicAuthenticator<String> authentication = new HttpBasicAuthenticator<String>("My realm") {
private final String hardcodedPassword = "correcthorsebatterystaple";
public CompletionStage<Optional<String>> authenticate(BasicCredentials credentials) {
// this is where your actual authentication logic would go
if (credentials.available() && // no anonymous access
credentials.verify(hardcodedPassword)) {
return authenticateAs(credentials.identifier());
} else {
return refuseAccess();
}
}
};
final Route route =
authentication.route(
handleWith1(
authentication,
new Handler1<String>() {
public RouteResult apply(RequestContext ctx, String user) {
return ctx.complete("Hello " + user + "!");
}
}
)
authenticateBasic("My realm", this::authenticate, user ->
complete("Hello " + user + "!")
);
// tests:
final HttpRequest okRequest =
HttpRequest

View file

@ -6,18 +6,11 @@ package docs.http.javadsl.server;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.dispatch.OnFailure;
import akka.http.javadsl.ConnectHttp;
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.ContentTypes;
import akka.http.javadsl.model.HttpMethods;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.model.Uri;
import akka.http.scaladsl.model.HttpEntity;
import akka.japi.function.Function;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
@ -34,180 +27,182 @@ import java.util.concurrent.TimeUnit;
@SuppressWarnings("unused")
public class HttpServerExampleDocTest {
public static void bindingExample() throws Exception {
//#binding-example
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
public static void bindingExample() throws Exception {
//#binding-example
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("localhost", 8080), materializer);
Source<IncomingConnection, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("localhost", 8080), materializer);
CompletionStage<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(connection -> {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}
)).run(materializer);
//#binding-example
serverBindingFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
}
public static void bindingFailureExample() throws Exception {
//#binding-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("localhost", 80), materializer);
CompletionStage<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(connection -> {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}
)).run(materializer);
serverBindingFuture.whenCompleteAsync((binding, failure) -> {
// possibly report the failure somewhere...
}, system.dispatcher());
//#binding-failure-handling
serverBindingFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
}
public static void connectionSourceFailureExample() throws Exception {
//#incoming-connections-source-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("localhost", 8080), materializer);
Flow<IncomingConnection, IncomingConnection, NotUsed> failureDetection =
Flow.of(IncomingConnection.class).watchTermination((notUsed, termination) -> {
termination.whenComplete((done, cause) -> {
if (cause != null) {
// signal the failure to external monitoring service!
}
});
return NotUsed.getInstance();
});
CompletionStage<ServerBinding> serverBindingFuture =
serverSource
.via(failureDetection) // feed signals through our custom stage
.to(Sink.foreach(connection -> {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}))
.run(materializer);
//#incoming-connections-source-failure-handling
serverBindingFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
}
public static void connectionStreamFailureExample() throws Exception {
//#connection-stream-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("localhost", 8080), materializer);
Flow<HttpRequest, HttpRequest, NotUsed> failureDetection =
Flow.of(HttpRequest.class)
.watchTermination((notUsed, termination) -> {
termination.whenComplete((done, cause) -> {
if (cause != null) {
// signal the failure to external monitoring service!
}
});
return NotUsed.getInstance();
});
Flow<HttpRequest, HttpResponse, NotUsed> httpEcho =
Flow.of(HttpRequest.class)
.via(failureDetection)
.map(request -> {
Source<ByteString, Object> bytes = request.entity().getDataBytes();
HttpEntity.Chunked entity = HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, bytes);
return HttpResponse.create()
.withEntity(entity);
});
CompletionStage<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(conn -> {
System.out.println("Accepted new connection from " + conn.remoteAddress());
conn.handleWith(httpEcho, materializer);
}
)).run(materializer);
//#connection-stream-failure-handling
serverBindingFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
}
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, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("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(ContentTypes.TEXT_HTML_UTF8,
"<html><body>Hello world!</body></html>");
else if (uri.path().equals("/hello")) {
String name = uri.query().get("name").orElse("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
CompletionStage<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(connection -> {
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
serverBindingFuture.toCompletableFuture().get(1, TimeUnit.SECONDS); // will throw if binding fails
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
} finally {
system.terminate();
CompletionStage<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(connection -> {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}
)).run(materializer);
//#binding-example
serverBindingFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
}
public static void bindingFailureExample() throws Exception {
//#binding-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("localhost", 80), materializer);
CompletionStage<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(connection -> {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}
)).run(materializer);
serverBindingFuture.whenCompleteAsync((binding, failure) -> {
// possibly report the failure somewhere...
}, system.dispatcher());
//#binding-failure-handling
serverBindingFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
}
public static void connectionSourceFailureExample() throws Exception {
//#incoming-connections-source-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("localhost", 8080), materializer);
Flow<IncomingConnection, IncomingConnection, NotUsed> failureDetection =
Flow.of(IncomingConnection.class).watchTermination((notUsed, termination) -> {
termination.whenComplete((done, cause) -> {
if (cause != null) {
// signal the failure to external monitoring service!
}
});
return NotUsed.getInstance();
});
CompletionStage<ServerBinding> serverBindingFuture =
serverSource
.via(failureDetection) // feed signals through our custom stage
.to(Sink.foreach(connection -> {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}))
.run(materializer);
//#incoming-connections-source-failure-handling
serverBindingFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
}
public static void connectionStreamFailureExample() throws Exception {
//#connection-stream-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("localhost", 8080), materializer);
Flow<HttpRequest, HttpRequest, NotUsed> failureDetection =
Flow.of(HttpRequest.class)
.watchTermination((notUsed, termination) -> {
termination.whenComplete((done, cause) -> {
if (cause != null) {
// signal the failure to external monitoring service!
}
});
return NotUsed.getInstance();
});
Flow<HttpRequest, HttpResponse, NotUsed> httpEcho =
Flow.of(HttpRequest.class)
.via(failureDetection)
.map(request -> {
Source<ByteString, Object> bytes = request.entity().getDataBytes();
HttpEntity.Chunked entity = HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, bytes);
return HttpResponse.create()
.withEntity(entity);
});
CompletionStage<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(conn -> {
System.out.println("Accepted new connection from " + conn.remoteAddress());
conn.handleWith(httpEcho, materializer);
}
)).run(materializer);
//#connection-stream-failure-handling
serverBindingFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
}
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, CompletionStage<ServerBinding>> serverSource =
Http.get(system).bind(ConnectHttp.toHost("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(ContentTypes.TEXT_HTML_UTF8,
"<html><body>Hello world!</body></html>");
} else if (uri.path().equals("/hello")) {
String name = uri.query().get("name").orElse("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
CompletionStage<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(connection -> {
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
serverBindingFuture.toCompletableFuture().get(1, TimeUnit.SECONDS); // will throw if binding fails
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
} finally {
system.terminate();
}
public static void main(String[] args) throws Exception {
fullServerExample();
}
}
public static void main(String[] args) throws Exception {
fullServerExample();
}
}

View file

@ -5,62 +5,36 @@ package docs.http.javadsl.server;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.headers.Host;
import akka.http.javadsl.model.headers.OAuth2BearerToken;
import akka.http.javadsl.server.Handler1;
import akka.http.javadsl.server.RequestContext;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.server.RouteResult;
import akka.http.javadsl.server.values.BasicCredentials;
import akka.http.javadsl.server.values.HttpBasicAuthenticator;
import akka.http.javadsl.server.values.OAuth2Authenticator;
import akka.http.javadsl.server.values.OAuth2Credentials;
import akka.http.javadsl.testkit.JUnitRouteTest;
import akka.http.scaladsl.model.headers.Authorization;
import java.util.Optional;
import java.util.concurrent.CompletionStage;
import org.junit.Test;
import scala.Option;
import scala.concurrent.Future;
public class OAuth2AuthenticatorExample extends JUnitRouteTest {
private final String hardcodedToken = "token";
private Optional<String> authenticate(Optional<ProvidedCredentials> creds) {
// this is where your actual authentication logic would go, looking up the user
// based on the token or something in that direction
// We will not allow anonymous access.
return creds
.filter(c -> c.verify(hardcodedToken)) //
.map(c -> c.identifier()); // Provide the "identifier" down to the inner route
// (for OAuth2, that's actually just the token)
}
@Test
public void testOAuth2Authenticator() {
//#oauth2-authenticator-java
final OAuth2Authenticator<String> authentication = new OAuth2Authenticator<String>("My realm") {
private final String hardcodedToken = "token";
@Override
public CompletionStage<Optional<String>> authenticate(OAuth2Credentials credentials) {
// this is where your actual authentication logic would go, looking up the user
// based on the token or something in that direction
if (credentials.available() && // no anonymous access
credentials.verify(hardcodedToken)) {
// not a secret + identity pair, so this is actually the token
return authenticateAs(credentials.identifier());
} else {
return refuseAccess();
}
}
};
final Route route =
authentication.route(
handleWith1(
authentication,
new Handler1<String>() {
public RouteResult apply(RequestContext ctx, String token) {
return ctx.complete("The secret token is: " + token);
}
}
)
);
authenticateOAuth2("My realm", this::authenticate, token ->
complete("The secret token is: " + token)
);
// tests:

View file

@ -5,73 +5,75 @@
package docs.http.javadsl.server;
import akka.http.javadsl.model.StatusCodes;
import akka.http.javadsl.server.Handler1;
import akka.http.javadsl.server.values.PathMatcher;
import akka.http.javadsl.server.values.PathMatchers;
import akka.http.javadsl.server.PathMatchers;
import akka.http.javadsl.testkit.JUnitRouteTest;
import org.junit.Test;
public class PathDirectiveExampleTest extends JUnitRouteTest {
@Test
public void testPathPrefix() {
//#path-examples
// matches "/test"
path("test").route(
completeWithStatus(StatusCodes.OK)
);
@Test
public void testPathPrefix() {
//#path-examples
// matches "/test"
path("test", () ->
complete(StatusCodes.OK)
);
// matches "/test", as well
path(PathMatchers.segment("test")).route(
completeWithStatus(StatusCodes.OK)
);
// matches "/test", as well
path(PathMatchers.segment("test"), () ->
complete(StatusCodes.OK)
);
// matches "/admin/user"
path("admin", "user").route(
completeWithStatus(StatusCodes.OK)
);
// matches "/admin/user"
path(PathMatchers.segment("admin")
.slash("user"), () ->
complete(StatusCodes.OK)
);
// matches "/admin/user", as well
pathPrefix("admin").route(
path("user").route(
completeWithStatus(StatusCodes.OK)
)
);
// matches "/admin/user", as well
pathPrefix("admin", () ->
path("user", () ->
complete(StatusCodes.OK)
)
);
// matches "/admin/user/<user-id>"
Handler1<Integer> completeWithUserId =
(ctx, userId) -> ctx.complete("Hello user " + userId);
PathMatcher<Integer> userId = PathMatchers.intValue();
pathPrefix("admin", "user").route(
path(userId).route(
handleWith1(userId, completeWithUserId)
)
);
// matches "/admin/user/<user-id>"
path(PathMatchers.segment("admin")
.slash("user")
.slash(PathMatchers.integerSegment()), userId -> {
return complete("Hello user " + userId);
}
);
// matches "/admin/user/<user-id>", as well
path("admin", "user", userId).route(
handleWith1(userId, completeWithUserId)
);
// matches "/admin/user/<user-id>", as well
pathPrefix("admin", () ->
path("user", () ->
path(PathMatchers.integerSegment(), userId ->
complete("Hello user " + userId)
)
)
);
// never matches
path("admin").route( // oops this only matches "/admin"
path("user").route(
completeWithStatus(StatusCodes.OK)
)
);
// never matches
path("admin", () -> // oops this only matches "/admin", and no sub-paths
path("user", () ->
complete(StatusCodes.OK)
)
);
// matches "/user/" with the first subroute, "/user" (without a trailing slash)
// with the second subroute, and "/user/<user-id>" with the last one.
pathPrefix("user").route(
pathSingleSlash().route(
completeWithStatus(StatusCodes.OK)
),
pathEnd().route(
completeWithStatus(StatusCodes.OK)
),
path(userId).route(
handleWith1(userId, completeWithUserId)
)
);
//#path-examples
}
}
// matches "/user/" with the first subroute, "/user" (without a trailing slash)
// with the second subroute, and "/user/<user-id>" with the last one.
pathPrefix("user", () -> route(
pathSingleSlash(() ->
complete(StatusCodes.OK)
),
pathEnd(() ->
complete(StatusCodes.OK)
),
path(PathMatchers.integerSegment(), userId ->
complete("Hello user " + userId)
)
));
//#path-examples
}
}

View file

@ -5,6 +5,7 @@
package docs.http.javadsl.server;
//#websocket-example-using-core
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.CompletionStage;
@ -12,11 +13,6 @@ import java.util.concurrent.TimeUnit;
import akka.NotUsed;
import akka.http.javadsl.ConnectHttp;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.FiniteDuration;
import scala.runtime.BoxedUnit;
import akka.japi.Function;
import akka.japi.JavaPartialFunction;
@ -34,66 +30,76 @@ import akka.http.javadsl.model.ws.Message;
import akka.http.javadsl.model.ws.TextMessage;
import akka.http.javadsl.model.ws.WebSocket;
@SuppressWarnings("Convert2MethodRef")
public class WebSocketCoreExample {
//#websocket-handling
public static HttpResponse handleRequest(HttpRequest request) {
System.out.println("Handling request to " + request.getUri());
//#websocket-handling
public static HttpResponse handleRequest(HttpRequest request) {
System.out.println("Handling request to " + request.getUri());
if (request.getUri().path().equals("/greeter"))
return WebSocket.handleWebSocketRequestWith(request, greeter());
else
return HttpResponse.create().withStatus(404);
if (request.getUri().path().equals("/greeter")) {
final Flow<Message, Message, NotUsed> greeterFlow = greeter();
return WebSocket.handleWebSocketRequestWith(request, greeterFlow);
} else {
return HttpResponse.create().withStatus(404);
}
//#websocket-handling
}
//#websocket-handling
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create();
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create();
try {
final Materializer materializer = ActorMaterializer.create(system);
try {
final Materializer materializer = ActorMaterializer.create(system);
CompletionStage<ServerBinding> serverBindingFuture =
Http.get(system).bindAndHandleSync(
new Function<HttpRequest, HttpResponse>() {
public HttpResponse apply(HttpRequest request) throws Exception {
return handleRequest(request);
}
}, ConnectHttp.toHost("localhost", 8080), materializer);
final Function<HttpRequest, HttpResponse> handler = request -> handleRequest(request);
CompletionStage<ServerBinding> serverBindingFuture =
Http.get(system).bindAndHandleSync(
handler, ConnectHttp.toHost("localhost", 8080), materializer);
// will throw if binding fails
serverBindingFuture.toCompletableFuture().get(1, TimeUnit.SECONDS);
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
} finally {
system.terminate();
}
// will throw if binding fails
serverBindingFuture.toCompletableFuture().get(1, TimeUnit.SECONDS);
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
} finally {
system.terminate();
}
}
//#websocket-handler
/**
* A handler that treats incoming messages as a name,
* and responds with a greeting to that name
*/
public static Flow<Message, Message, NotUsed> greeter() {
return
Flow.<Message>create()
.collect(new JavaPartialFunction<Message, Message>() {
@Override
public Message apply(Message msg, boolean isCheck) throws Exception {
if (isCheck)
if (msg.isText()) return null;
else throw noMatch();
else
return handleTextMessage(msg.asTextMessage());
}
});
//#websocket-handler
/**
* A handler that treats incoming messages as a name,
* and responds with a greeting to that name
*/
public static Flow<Message, Message, NotUsed> greeter() {
return
Flow.<Message>create()
.collect(new JavaPartialFunction<Message, Message>() {
@Override
public Message apply(Message msg, boolean isCheck) throws Exception {
if (isCheck) {
if (msg.isText()) {
return null;
} else {
throw noMatch();
}
} else {
return handleTextMessage(msg.asTextMessage());
}
}
});
}
public static TextMessage handleTextMessage(TextMessage msg) {
if (msg.isStrict()) // optimization that directly creates a simple response...
{
return TextMessage.create("Hello " + msg.getStrictText());
} else // ... this would suffice to handle all text messages in a streaming fashion
{
return TextMessage.create(Source.single("Hello ").concat(msg.getStreamedText()));
}
public static TextMessage handleTextMessage(TextMessage msg) {
if (msg.isStrict()) // optimization that directly creates a simple response...
return TextMessage.create("Hello "+msg.getStrictText());
else // ... this would suffice to handle all text messages in a streaming fashion
return TextMessage.create(Source.single("Hello ").concat(msg.getStreamedText()));
}
//#websocket-handler
}
//#websocket-handler
}
//#websocket-example-using-core
//#websocket-example-using-core

View file

@ -4,51 +4,51 @@
package docs.http.javadsl.server;
import akka.NotUsed;
import akka.http.javadsl.server.AllDirectives;
import akka.http.javadsl.server.Route;
import akka.japi.JavaPartialFunction;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Source;
import akka.http.javadsl.model.ws.Message;
import akka.http.javadsl.model.ws.TextMessage;
import akka.http.javadsl.server.HttpApp;
public class WebSocketRoutingExample extends AllDirectives {
public class WebSocketRoutingExample extends HttpApp {
//#websocket-route
@Override
public Route createRoute() {
return
path("greeter").route(
handleWebSocketMessages(greeter())
);
}
//#websocket-route
//#websocket-route
public Route createRoute() {
return
path("greeter", () ->
handleWebSocketMessages(greeter())
);
}
//#websocket-route
/**
* A handler that treats incoming messages as a name,
* and responds with a greeting to that name
*/
public static Flow<Message, Message, ?> greeter() {
return
Flow.<Message>create()
.collect(new JavaPartialFunction<Message, Message>() {
@Override
public Message apply(Message msg, boolean isCheck) throws Exception {
if (isCheck)
if (msg.isText()) return null;
else throw noMatch();
else
return handleTextMessage(msg.asTextMessage());
}
});
}
public static TextMessage handleTextMessage(TextMessage msg) {
if (msg.isStrict()) // optimization that directly creates a simple response...
return TextMessage.create("Hello "+msg.getStrictText());
else // ... this would suffice to handle all text messages in a streaming fashion
return TextMessage.create(Source.single("Hello ").concat(msg.getStreamedText()));
/**
* A handler that treats incoming messages as a name,
* and responds with a greeting to that name
*/
public static Flow<Message, Message, NotUsed> greeter() {
return
Flow.<Message>create()
.collect(new JavaPartialFunction<Message, Message>() {
@Override
public Message apply(Message msg, boolean isCheck) throws Exception {
if (isCheck) {
if (msg.isText()) return null;
else throw noMatch();
} else return handleTextMessage(msg.asTextMessage());
}
});
}
public static TextMessage handleTextMessage(TextMessage msg) {
if (msg.isStrict()) // optimization that directly creates a simple response...
{
return TextMessage.create("Hello " + msg.getStrictText());
} else // ... this would suffice to handle all text messages in a streaming fashion
{
return TextMessage.create(Source.single("Hello ").concat(msg.getStreamedText()));
}
}
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
*/
package docs.http.javadsl.server.directives;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.StatusCodes;
import akka.http.javadsl.model.headers.RawHeader;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.testkit.JUnitRouteTest;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
import java.util.function.Function;
public class CustomDirectivesExamplesTest extends JUnitRouteTest {
//#labeling-1
public Route getOrPut(Supplier<Route> inner) {
return get(inner).orElse(put(inner));
}
//#
@Test
public void testLabeling() {
// tests:
//#labeling-2
Route route = getOrPut(() -> complete("ok"));
//#
testRoute(route).run(HttpRequest.GET("/"))
.assertStatusCode(StatusCodes.OK);
testRoute(route).run(HttpRequest.PUT("/"))
.assertStatusCode(StatusCodes.OK);
}
public static class MyCredentials {
private final String userId;
private final String secret;
public MyCredentials(String userId, String secret) {
this.userId = userId;
this.secret = secret;
}
public String getUserId() {
return userId;
}
public boolean safeSecretVerification(String correct) {
// of course this is not what you would do in a real app
return correct.equals(secret);
}
}
public static enum MyRole {
USER,
ADMIN
}
//#composition-1
// the composed custom directive
/**
* @param authenticate A function returns a set of roles for the credentials of a user
* @param inner Inner route to execute if the provided credentials has the given role
* if not, the request is completed with a
*/
public Route headerBasedAuth(Function<MyCredentials, Set<MyRole>> authenticate, MyRole requiredRole, Supplier<Route> inner) {
return headerValueByName("X-My-User-Id", (userId) -> {
return headerValueByName("X-My-User-Secret", (secret) -> {
Set<MyRole> userRoles = authenticate.apply(new MyCredentials(userId, secret));
if (userRoles.contains(requiredRole)) {
return inner.get();
} else {
return complete(StatusCodes.FORBIDDEN, "Role " + requiredRole + " required for access");
}
});
});
}
//#
@Test
public void testComposition() {
// tests:
//#composition-2
// a function for authentication
Function<MyCredentials, Set<MyRole>> authLogic =
(credentials) -> {
if (credentials.userId.equals("admin") && credentials.safeSecretVerification("secret"))
return new HashSet<>(Arrays.asList(MyRole.USER, MyRole.ADMIN));
else
return Collections.emptySet();
};
// and then using the custom route
Route route = get(() ->
path("admin", () ->
headerBasedAuth(authLogic, MyRole.ADMIN, () -> complete(StatusCodes.OK, "admin stuff"))
)
);
//#
testRoute(route).run(HttpRequest.GET("/admin"))
.assertStatusCode(StatusCodes.BAD_REQUEST);
testRoute(route).run(HttpRequest.GET("/admin").addHeaders(
Arrays.asList(RawHeader.create("X-My-User-Id", "user"), RawHeader.create("X-My-User-Secret", "wrong"))))
.assertStatusCode(StatusCodes.FORBIDDEN);
testRoute(route).run(HttpRequest.GET("/admin").addHeaders(
Arrays.asList(RawHeader.create("X-My-User-Id", "admin"), RawHeader.create("X-My-User-Secret", "secret"))))
.assertStatusCode(StatusCodes.OK);
}
}

View file

@ -7,15 +7,14 @@ package docs.http.javadsl.server.directives;
import java.util.Arrays;
import java.util.regex.Pattern;
import akka.http.javadsl.model.HttpMethod;
import org.junit.Test;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.StatusCodes;
import akka.http.javadsl.model.headers.Host;
import akka.http.javadsl.server.*;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.testkit.JUnitRouteTest;
import org.junit.Test;
public class HostDirectivesExamplesTest extends JUnitRouteTest {
@Test
@ -23,7 +22,7 @@ public class HostDirectivesExamplesTest extends JUnitRouteTest {
//#host1
final Route matchListOfHosts = host(
Arrays.asList("api.company.com", "rest.company.com"),
completeWithStatus(StatusCodes.OK));
() -> complete(StatusCodes.OK));
testRoute(matchListOfHosts).run(HttpRequest.GET("/").addHeader(Host.create("api.company.com")))
.assertStatusCode(StatusCodes.OK);
@ -34,7 +33,7 @@ public class HostDirectivesExamplesTest extends JUnitRouteTest {
public void testHostPredicate() {
//#host2
final Route shortOnly = host(hostname -> hostname.length() < 10,
completeWithStatus(StatusCodes.OK));
() -> complete(StatusCodes.OK));
testRoute(shortOnly).run(HttpRequest.GET("/").addHeader(Host.create("short.com")))
.assertStatusCode(StatusCodes.OK);
@ -47,10 +46,9 @@ public class HostDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testExtractHost() {
//#extractHostname
final RequestVal<String> host = RequestVals.host();
final Route route = handleWith1(host,
(ctx, hn) -> ctx.complete("Hostname: " + hn));
final Route route = extractHost(hn ->
complete("Hostname: " + hn));
testRoute(route).run(HttpRequest.GET("/").addHeader(Host.create("company.com", 9090)))
.assertEntity("Hostname: company.com");
@ -60,18 +58,12 @@ public class HostDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testMatchAndExtractHost() {
//#matchAndExtractHost
final RequestVal<String> hostPrefix = RequestVals
.matchAndExtractHost(Pattern.compile("api|rest"));
final Route hostPrefixRoute = handleWith1(hostPrefix,
(ctx, prefix) -> ctx.complete("Extracted prefix: " + prefix));
final Route hostPrefixRoute = host(Pattern.compile("api|rest"), prefix ->
complete("Extracted prefix: " + prefix));
final RequestVal<String> hostPart = RequestVals.matchAndExtractHost(Pattern
.compile("public.(my|your)company.com"));
final Route hostPartRoute = handleWith1(
hostPart,
(ctx, captured) -> ctx.complete("You came through " + captured
final Route hostPartRoute = host(Pattern.compile("public.(my|your)company.com"), captured ->
complete("You came through " + captured
+ " company"));
final Route route = route(hostPrefixRoute, hostPartRoute);
@ -90,9 +82,10 @@ public class HostDirectivesExamplesTest extends JUnitRouteTest {
public void testFailingMatchAndExtractHost() {
//#failing-matchAndExtractHost
// this will throw IllegalArgumentException
final RequestVal<String> hostRegex = RequestVals
.matchAndExtractHost(Pattern
.compile("server-([0-9]).company.(com|net|org)"));
final Route hostRegex = host(Pattern.compile("server-([0-9]).company.(com|net|org)"), s ->
// will not reach here
complete(s)
);
//#failing-matchAndExtractHost
}

View file

@ -4,20 +4,19 @@
package docs.http.javadsl.server.directives;
import akka.http.javadsl.model.HttpMethod;
import org.junit.Test;
import akka.http.javadsl.model.HttpMethods;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.StatusCodes;
import akka.http.javadsl.server.*;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.testkit.JUnitRouteTest;
import org.junit.Test;
public class MethodDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testDelete() {
//#delete
final Route route = delete(complete("This is a DELETE request."));
final Route route = delete(() -> complete("This is a DELETE request."));
testRoute(route).run(HttpRequest.DELETE("/")).assertEntity(
"This is a DELETE request.");
@ -27,7 +26,7 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testGet() {
//#get
final Route route = get(complete("This is a GET request."));
final Route route = get(() -> complete("This is a GET request."));
testRoute(route).run(HttpRequest.GET("/")).assertEntity(
"This is a GET request.");
@ -37,7 +36,7 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testHead() {
//#head
final Route route = head(complete("This is a HEAD request."));
final Route route = head(() -> complete("This is a HEAD request."));
testRoute(route).run(HttpRequest.HEAD("/")).assertEntity(
"This is a HEAD request.");
@ -47,7 +46,7 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testOptions() {
//#options
final Route route = options(complete("This is a OPTIONS request."));
final Route route = options(() -> complete("This is a OPTIONS request."));
testRoute(route).run(HttpRequest.OPTIONS("/")).assertEntity(
"This is a OPTIONS request.");
@ -57,7 +56,7 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testPatch() {
//#patch
final Route route = patch(complete("This is a PATCH request."));
final Route route = patch(() -> complete("This is a PATCH request."));
testRoute(route).run(HttpRequest.PATCH("/").withEntity("patch content"))
.assertEntity("This is a PATCH request.");
@ -67,7 +66,7 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testPost() {
//#post
final Route route = post(complete("This is a POST request."));
final Route route = post(() -> complete("This is a POST request."));
testRoute(route).run(HttpRequest.POST("/").withEntity("post content"))
.assertEntity("This is a POST request.");
@ -77,7 +76,7 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testPut() {
//#put
final Route route = put(complete("This is a PUT request."));
final Route route = put(() -> complete("This is a PUT request."));
testRoute(route).run(HttpRequest.PUT("/").withEntity("put content"))
.assertEntity("This is a PUT request.");
@ -88,7 +87,7 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
public void testMethodExample() {
//#method-example
final Route route = method(HttpMethods.PUT,
complete("This is a PUT request."));
() -> complete("This is a PUT request."));
testRoute(route).run(HttpRequest.PUT("/").withEntity("put content"))
.assertEntity("This is a PUT request.");
@ -101,15 +100,15 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
@Test
public void testExtractMethodExample() {
//#extractMethod
final RequestVal<HttpMethod> requestMethod = RequestVals.requestMethod();
final Route otherMethod = handleWith1(
requestMethod,
(ctx, method) -> ctx.complete("This " + method.value()
+ " request, clearly is not a GET!"));
final Route route = route(get(complete("This is a GET request.")),
otherMethod);
final Route route = route(
get(() ->
complete("This is a GET request.")
),
extractMethod(method ->
complete("This " + method.value() + " request, clearly is not a GET!")
)
);
testRoute(route).run(HttpRequest.GET("/")).assertEntity(
"This is a GET request.");
@ -121,4 +120,31 @@ public class MethodDirectivesExamplesTest extends JUnitRouteTest {
"This HEAD request, clearly is not a GET!");
//#extractMethod
}
@Test
public void testOverrideMethodWithParameter() {
//#overrideMethodWithParameter
final Route route = route(
overrideMethodWithParameter("method", () ->
route(
get(() -> complete("This looks like a GET request.")),
post(() -> complete("This looks like a POST request."))
)
)
);
// tests:
testRoute(route).run(HttpRequest.GET("/?method=POST")).assertEntity(
"This looks like a POST request.");
testRoute(route).run(HttpRequest.POST("/?method=get"))
.assertEntity("This looks like a GET request.");
testRoute(route).run(HttpRequest.GET("/?method=hallo")).assertEntity(
"The server either does not recognize the request method, or it lacks the ability to fulfill the request.");
//#overrideMethodWithParameter
}
}

View file

@ -5,29 +5,51 @@
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");
import akka.actor.ActorSystem;
import akka.http.javadsl.ConnectHttp;
import akka.http.javadsl.Http;
import akka.http.javadsl.server.AllDirectives;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.server.StringUnmarshallers;
import akka.http.javadsl.server.examples.simple.SimpleServerApp;
import akka.stream.ActorMaterializer;
public RouteResult add(RequestContext ctx, double x, double y) {
return ctx.complete("x + y = " + (x + y));
}
import java.io.IOException;
@Override
public Route createRoute() {
return
route(
get(
pathPrefix("calculator").route(
path("add").route(
handleReflectively(this, "add", x, y)
)
)
)
);
}
public class MyAppService extends AllDirectives {
public String add(double x, double y) {
return "x + y = " + (x + y);
}
public Route createRoute() {
return
get(() ->
pathPrefix("calculator", () ->
path("add", () ->
parameter(StringUnmarshallers.DOUBLE, "x", x ->
parameter(StringUnmarshallers.DOUBLE, "y", y ->
complete(add(x, y))
)
)
)
)
);
}
public static void main(String[] args) throws IOException {
final ActorSystem system = ActorSystem.create();
final ActorMaterializer materializer = ActorMaterializer.create(system);
final SimpleServerApp app = new SimpleServerApp();
final ConnectHttp host = ConnectHttp.toHost("127.0.0.1");
Http.get(system).bindAndHandle(app.createRoute().flow(system, materializer), host, materializer);
System.console().readLine("Type RETURN to exit...");
system.terminate();
}
}
//#simple-app
//#simple-app