Remove Akka-HTTP sources from akka/akka, moving to akka/akka-http! (#21690)
This commit is contained in:
parent
09a6d2ede1
commit
a6a5556a8f
1155 changed files with 20 additions and 96517 deletions
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl;
|
||||
|
||||
import akka.Done;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.http.javadsl.ConnectHttp;
|
||||
import akka.http.javadsl.HostConnectionPool;
|
||||
import akka.japi.Pair;
|
||||
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import akka.stream.Materializer;
|
||||
import akka.util.ByteString;
|
||||
import scala.compat.java8.FutureConverters;
|
||||
import scala.concurrent.ExecutionContextExecutor;
|
||||
import scala.concurrent.Future;
|
||||
import akka.stream.javadsl.*;
|
||||
import akka.http.javadsl.OutgoingConnection;
|
||||
import akka.http.javadsl.Http;
|
||||
|
||||
import static akka.http.javadsl.ConnectHttp.toHost;
|
||||
import static akka.pattern.PatternsCS.*;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
//#manual-entity-consume-example-1
|
||||
import java.io.File;
|
||||
import akka.actor.ActorSystem;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.javadsl.Framing;
|
||||
import akka.http.javadsl.model.*;
|
||||
import scala.concurrent.duration.FiniteDuration;
|
||||
import scala.util.Try;
|
||||
//#manual-entity-consume-example-1
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HttpClientExampleDocTest {
|
||||
|
||||
HttpResponse responseFromSomewhere() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void manualEntityComsumeExample() {
|
||||
//#manual-entity-consume-example-1
|
||||
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ExecutionContextExecutor dispatcher = system.dispatcher();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final HttpResponse response = responseFromSomewhere();
|
||||
|
||||
final Function<ByteString, ByteString> transformEachLine = line -> line /* some transformation here */;
|
||||
|
||||
final int maximumFrameLength = 256;
|
||||
|
||||
response.entity().getDataBytes()
|
||||
.via(Framing.delimiter(ByteString.fromString("\n"), maximumFrameLength, FramingTruncation.ALLOW))
|
||||
.map(transformEachLine::apply)
|
||||
.runWith(FileIO.toPath(new File("/tmp/example.out").toPath()), materializer);
|
||||
//#manual-entity-consume-example-1
|
||||
}
|
||||
|
||||
private
|
||||
//#manual-entity-consume-example-2
|
||||
final class ExamplePerson {
|
||||
final String name;
|
||||
public ExamplePerson(String name) { this.name = name; }
|
||||
}
|
||||
|
||||
public ExamplePerson parse(ByteString line) {
|
||||
return new ExamplePerson(line.utf8String());
|
||||
}
|
||||
//#manual-entity-consume-example-2
|
||||
|
||||
void manualEntityConsumeExample2() {
|
||||
//#manual-entity-consume-example-2
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ExecutionContextExecutor dispatcher = system.dispatcher();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final HttpResponse response = responseFromSomewhere();
|
||||
|
||||
// toStrict to enforce all data be loaded into memory from the connection
|
||||
final CompletionStage<HttpEntity.Strict> strictEntity = response.entity()
|
||||
.toStrict(FiniteDuration.create(3, TimeUnit.SECONDS).toMillis(), materializer);
|
||||
|
||||
// while API remains the same to consume dataBytes, now they're in memory already:
|
||||
|
||||
final CompletionStage<ExamplePerson> person =
|
||||
strictEntity
|
||||
.thenCompose(strict ->
|
||||
strict.getDataBytes()
|
||||
.runFold(ByteString.empty(), (acc, b) -> acc.concat(b), materializer)
|
||||
.thenApply(this::parse)
|
||||
);
|
||||
|
||||
//#manual-entity-consume-example-2
|
||||
}
|
||||
|
||||
void manualEntityDiscardExample1() {
|
||||
//#manual-entity-discard-example-1
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ExecutionContextExecutor dispatcher = system.dispatcher();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final HttpResponse response = responseFromSomewhere();
|
||||
|
||||
final HttpMessage.DiscardedEntity discarded = response.discardEntityBytes(materializer);
|
||||
|
||||
discarded.completionStage().whenComplete((done, ex) -> {
|
||||
System.out.println("Entity discarded completely!");
|
||||
});
|
||||
//#manual-entity-discard-example-1
|
||||
}
|
||||
|
||||
void manualEntityDiscardExample2() {
|
||||
//#manual-entity-discard-example-2
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ExecutionContextExecutor dispatcher = system.dispatcher();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final HttpResponse response = responseFromSomewhere();
|
||||
|
||||
final CompletionStage<Done> discardingComplete = response.entity().getDataBytes().runWith(Sink.ignore(), materializer);
|
||||
|
||||
discardingComplete.whenComplete((done, ex) -> {
|
||||
System.out.println("Entity discarded completely!");
|
||||
});
|
||||
//#manual-entity-discard-example-2
|
||||
}
|
||||
|
||||
|
||||
// compile only test
|
||||
public void testConstructRequest() {
|
||||
//#outgoing-connection-example
|
||||
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final Flow<HttpRequest, HttpResponse, CompletionStage<OutgoingConnection>> connectionFlow =
|
||||
Http.get(system).outgoingConnection(toHost("akka.io", 80));
|
||||
final CompletionStage<HttpResponse> responseFuture =
|
||||
Source.single(HttpRequest.create("/"))
|
||||
.via(connectionFlow)
|
||||
.runWith(Sink.<HttpResponse>head(), materializer);
|
||||
//#outgoing-connection-example
|
||||
}
|
||||
|
||||
// compile only test
|
||||
public void testHostLevelExample() {
|
||||
//#host-level-example
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
// construct a pool client flow with context type `Integer`
|
||||
final Flow<
|
||||
Pair<HttpRequest, Integer>,
|
||||
Pair<Try<HttpResponse>, Integer>,
|
||||
HostConnectionPool> poolClientFlow =
|
||||
Http.get(system).<Integer>cachedHostConnectionPool(toHost("akka.io", 80), materializer);
|
||||
|
||||
// construct a pool client flow with context type `Integer`
|
||||
|
||||
final CompletionStage<Pair<Try<HttpResponse>, Integer>> responseFuture =
|
||||
Source
|
||||
.single(Pair.create(HttpRequest.create("/"), 42))
|
||||
.via(poolClientFlow)
|
||||
.runWith(Sink.<Pair<Try<HttpResponse>, Integer>>head(), materializer);
|
||||
//#host-level-example
|
||||
}
|
||||
|
||||
// compile only test
|
||||
public void testSingleRequestExample() {
|
||||
//#single-request-example
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final Materializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final CompletionStage<HttpResponse> responseFuture =
|
||||
Http.get(system)
|
||||
.singleRequest(HttpRequest.create("http://akka.io"), materializer);
|
||||
//#single-request-example
|
||||
}
|
||||
|
||||
static
|
||||
//#single-request-in-actor-example
|
||||
class Myself extends AbstractActor {
|
||||
final Http http = Http.get(context().system());
|
||||
final ExecutionContextExecutor dispatcher = context().dispatcher();
|
||||
final Materializer materializer = ActorMaterializer.create(context());
|
||||
|
||||
public Myself() {
|
||||
receive(ReceiveBuilder
|
||||
.match(String.class, url -> {
|
||||
pipe(fetch (url), dispatcher).to(self());
|
||||
}).build());
|
||||
}
|
||||
|
||||
CompletionStage<HttpResponse> fetch(String url) {
|
||||
return http.singleRequest(HttpRequest.create(url), materializer);
|
||||
}
|
||||
}
|
||||
//#single-request-in-actor-example
|
||||
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.http.javadsl.*;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.HttpResponse;
|
||||
import akka.japi.Pair;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.Materializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Sink;
|
||||
import akka.stream.javadsl.Source;
|
||||
import com.typesafe.sslconfig.akka.AkkaSSLConfig;
|
||||
import scala.concurrent.ExecutionContextExecutor;
|
||||
import scala.util.Try;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import static akka.http.javadsl.ConnectHttp.toHost;
|
||||
import static akka.pattern.PatternsCS.pipe;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HttpsExamplesDocTest {
|
||||
|
||||
// compile only test
|
||||
public void testConstructRequest() {
|
||||
String unsafeHost = "example.com";
|
||||
//#disable-sni-connection
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ActorMaterializer mat = ActorMaterializer.create(system);
|
||||
final Http http = Http.get(system);
|
||||
|
||||
// WARNING: disabling SNI is a very bad idea, please don't unless you have a very good reason to.
|
||||
final AkkaSSLConfig defaultSSLConfig = AkkaSSLConfig.get(system);
|
||||
final AkkaSSLConfig badSslConfig = defaultSSLConfig
|
||||
.convertSettings(s -> s.withLoose(s.loose().withDisableSNI(true)));
|
||||
final HttpsConnectionContext badCtx = http.createClientHttpsContext(badSslConfig);
|
||||
|
||||
http.outgoingConnection(ConnectHttp.toHostHttps(unsafeHost).withCustomHttpsContext(badCtx));
|
||||
//#disable-sni-connection
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl;
|
||||
|
||||
import akka.util.ByteString;
|
||||
import org.junit.Test;
|
||||
|
||||
//#import-model
|
||||
import akka.http.javadsl.model.*;
|
||||
import akka.http.javadsl.model.headers.*;
|
||||
|
||||
import java.util.Optional;
|
||||
//#import-model
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ModelDocTest {
|
||||
@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(ContentTypes.TEXT_PLAIN_UTF8, "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 Optional<BasicHttpCredentials> getCredentialsOfRequest(HttpRequest request) {
|
||||
Optional<Authorization> auth = request.getHeader(Authorization.class);
|
||||
if (auth.isPresent() && auth.get().credentials() instanceof BasicHttpCredentials)
|
||||
return Optional.of((BasicHttpCredentials) auth.get().credentials());
|
||||
else
|
||||
return Optional.empty();
|
||||
}
|
||||
//#headers
|
||||
}
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl;
|
||||
|
||||
import akka.Done;
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.http.javadsl.Http;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.model.headers.Authorization;
|
||||
import akka.http.javadsl.model.ws.Message;
|
||||
import akka.http.javadsl.model.ws.TextMessage;
|
||||
import akka.http.javadsl.model.ws.WebSocketRequest;
|
||||
import akka.http.javadsl.model.ws.WebSocketUpgradeResponse;
|
||||
import akka.japi.Pair;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.Materializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Keep;
|
||||
import akka.stream.javadsl.Sink;
|
||||
import akka.stream.javadsl.Source;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class WebSocketClientExampleTest {
|
||||
|
||||
// compile only test
|
||||
public void testSingleWebSocketRequest() {
|
||||
//#single-WebSocket-request
|
||||
ActorSystem system = ActorSystem.create();
|
||||
Materializer materializer = ActorMaterializer.create(system);
|
||||
Http http = Http.get(system);
|
||||
|
||||
// print each incoming text message
|
||||
// would throw exception on non strict or binary message
|
||||
final Sink<Message, CompletionStage<Done>> printSink =
|
||||
Sink.foreach((message) ->
|
||||
System.out.println("Got message: " + message.asTextMessage().getStrictText())
|
||||
);
|
||||
|
||||
// send this as a message over the WebSocket
|
||||
final Source<Message, NotUsed> helloSource =
|
||||
Source.single(TextMessage.create("hello world"));
|
||||
|
||||
// the CompletionStage<Done> is the materialized value of Sink.foreach
|
||||
// and it is completed when the stream completes
|
||||
final Flow<Message, Message, CompletionStage<Done>> flow =
|
||||
Flow.fromSinkAndSourceMat(printSink, helloSource, Keep.left());
|
||||
|
||||
final Pair<CompletionStage<WebSocketUpgradeResponse>, CompletionStage<Done>> pair =
|
||||
http.singleWebSocketRequest(
|
||||
WebSocketRequest.create("ws://echo.websocket.org"),
|
||||
flow,
|
||||
materializer
|
||||
);
|
||||
|
||||
// The first value in the pair is a CompletionStage<WebSocketUpgradeResponse> that
|
||||
// completes when the WebSocket request has connected successfully (or failed)
|
||||
final CompletionStage<Done> connected = pair.first().thenApply(upgrade -> {
|
||||
// just like a regular http request we can access response status which is available via upgrade.response.status
|
||||
// status code 101 (Switching Protocols) indicates that server support WebSockets
|
||||
if (upgrade.response().status().equals(StatusCodes.SWITCHING_PROTOCOLS)) {
|
||||
return Done.getInstance();
|
||||
} else {
|
||||
throw new RuntimeException("Connection failed: " + upgrade.response().status());
|
||||
}
|
||||
});
|
||||
|
||||
// the second value is the completion of the sink from above
|
||||
// in other words, it completes when the WebSocket disconnects
|
||||
final CompletionStage<Done> closed = pair.second();
|
||||
|
||||
// in a real application you would not side effect here
|
||||
// and handle errors more carefully
|
||||
connected.thenAccept(done -> System.out.println("Connected"));
|
||||
closed.thenAccept(done -> System.out.println("Connection closed"));
|
||||
|
||||
//#single-WebSocket-request
|
||||
}
|
||||
|
||||
// compile only test
|
||||
public void halfClosedWebSocketClosingExample() {
|
||||
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final Materializer materializer = ActorMaterializer.create(system);
|
||||
final Http http = Http.get(system);
|
||||
|
||||
//#half-closed-WebSocket-closing
|
||||
|
||||
// we may expect to be able to to just tail
|
||||
// the server websocket output like this
|
||||
final Flow<Message, Message, NotUsed> flow =
|
||||
Flow.fromSinkAndSource(
|
||||
Sink.foreach(System.out::println),
|
||||
Source.empty());
|
||||
|
||||
http.singleWebSocketRequest(
|
||||
WebSocketRequest.create("ws://example.com:8080/some/path"),
|
||||
flow,
|
||||
materializer);
|
||||
|
||||
//#half-closed-WebSocket-closing
|
||||
}
|
||||
|
||||
public void halfClosedWebSocketWorkingExample() {
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final Materializer materializer = ActorMaterializer.create(system);
|
||||
final Http http = Http.get(system);
|
||||
|
||||
//#half-closed-WebSocket-working
|
||||
|
||||
// using Source.maybe materializes into a completable future
|
||||
// which will allow us to complete the source later
|
||||
final Flow<Message, Message, CompletableFuture<Optional<Message>>> flow =
|
||||
Flow.fromSinkAndSourceMat(
|
||||
Sink.foreach(System.out::println),
|
||||
Source.maybe(),
|
||||
Keep.right());
|
||||
|
||||
final Pair<CompletionStage<WebSocketUpgradeResponse>, CompletableFuture<Optional<Message>>> pair =
|
||||
http.singleWebSocketRequest(
|
||||
WebSocketRequest.create("ws://example.com:8080/some/path"),
|
||||
flow,
|
||||
materializer);
|
||||
|
||||
// at some later time we want to disconnect
|
||||
pair.second().complete(Optional.empty());
|
||||
//#half-closed-WebSocket-working
|
||||
}
|
||||
|
||||
public void halfClosedWebSocketFiniteWorkingExample() {
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final Materializer materializer = ActorMaterializer.create(system);
|
||||
final Http http = Http.get(system);
|
||||
|
||||
//#half-closed-WebSocket-finite
|
||||
|
||||
// emit "one" and then "two" and then keep the source from completing
|
||||
final Source<Message, CompletableFuture<Optional<Message>>> source =
|
||||
Source.from(Arrays.<Message>asList(TextMessage.create("one"), TextMessage.create("two")))
|
||||
.concatMat(Source.maybe(), Keep.right());
|
||||
|
||||
final Flow<Message, Message, CompletableFuture<Optional<Message>>> flow =
|
||||
Flow.fromSinkAndSourceMat(
|
||||
Sink.foreach(System.out::println),
|
||||
source,
|
||||
Keep.right());
|
||||
|
||||
final Pair<CompletionStage<WebSocketUpgradeResponse>, CompletableFuture<Optional<Message>>> pair =
|
||||
http.singleWebSocketRequest(
|
||||
WebSocketRequest.create("ws://example.com:8080/some/path"),
|
||||
flow,
|
||||
materializer);
|
||||
|
||||
// at some later time we want to disconnect
|
||||
pair.second().complete(Optional.empty());
|
||||
//#half-closed-WebSocket-finite
|
||||
}
|
||||
|
||||
|
||||
|
||||
// compile time only test
|
||||
public void testAuthorizedSingleWebSocketRequest() {
|
||||
Materializer materializer = null;
|
||||
Http http = null;
|
||||
|
||||
Flow<Message, Message, NotUsed> flow = null;
|
||||
|
||||
//#authorized-single-WebSocket-request
|
||||
http.singleWebSocketRequest(
|
||||
WebSocketRequest.create("ws://example.com:8080/some/path")
|
||||
.addHeader(Authorization.basic("johan", "correcthorsebatterystaple")),
|
||||
flow,
|
||||
materializer);
|
||||
//#authorized-single-WebSocket-request
|
||||
}
|
||||
|
||||
// compile time only test
|
||||
public void testWebSocketClientFlow() {
|
||||
//#WebSocket-client-flow
|
||||
ActorSystem system = ActorSystem.create();
|
||||
Materializer materializer = ActorMaterializer.create(system);
|
||||
Http http = Http.get(system);
|
||||
|
||||
// print each incoming text message
|
||||
// would throw exception on non strict or binary message
|
||||
Sink<Message, CompletionStage<Done>> printSink =
|
||||
Sink.foreach((message) ->
|
||||
System.out.println("Got message: " + message.asTextMessage().getStrictText())
|
||||
);
|
||||
|
||||
// send this as a message over the WebSocket
|
||||
Source<Message, NotUsed> helloSource =
|
||||
Source.single(TextMessage.create("hello world"));
|
||||
|
||||
|
||||
Flow<Message, Message, CompletionStage<WebSocketUpgradeResponse>> webSocketFlow =
|
||||
http.webSocketClientFlow(WebSocketRequest.create("ws://echo.websocket.org"));
|
||||
|
||||
|
||||
Pair<CompletionStage<WebSocketUpgradeResponse>, CompletionStage<Done>> pair =
|
||||
helloSource.viaMat(webSocketFlow, Keep.right())
|
||||
.toMat(printSink, Keep.both())
|
||||
.run(materializer);
|
||||
|
||||
|
||||
// The first value in the pair is a CompletionStage<WebSocketUpgradeResponse> that
|
||||
// completes when the WebSocket request has connected successfully (or failed)
|
||||
CompletionStage<WebSocketUpgradeResponse> upgradeCompletion = pair.first();
|
||||
|
||||
// the second value is the completion of the sink from above
|
||||
// in other words, it completes when the WebSocket disconnects
|
||||
CompletionStage<Done> closed = pair.second();
|
||||
|
||||
CompletionStage<Done> connected = upgradeCompletion.thenApply(upgrade->
|
||||
{
|
||||
// just like a regular http request we can access response status which is available via upgrade.response.status
|
||||
// status code 101 (Switching Protocols) indicates that server support WebSockets
|
||||
if (upgrade.response().status().equals(StatusCodes.SWITCHING_PROTOCOLS)) {
|
||||
return Done.getInstance();
|
||||
} else {
|
||||
throw new RuntimeException(("Connection failed: " + upgrade.response().status()));
|
||||
}
|
||||
});
|
||||
|
||||
// in a real application you would not side effect here
|
||||
// and handle errors more carefully
|
||||
connected.thenAccept(done -> System.out.println("Connected"));
|
||||
closed.thenAccept(done -> System.out.println("Connection closed"));
|
||||
|
||||
//#WebSocket-client-flow
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
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.unmarshalling.StringUnmarshallers;
|
||||
import akka.http.javadsl.unmarshalling.StringUnmarshaller;
|
||||
import akka.http.javadsl.unmarshalling.Unmarshaller;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.japi.Pair;
|
||||
|
||||
public class FormFieldRequestValsExampleTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testFormFieldVals() {
|
||||
//#simple
|
||||
|
||||
final Route route =
|
||||
formField("name", n ->
|
||||
formField(StringUnmarshallers.INTEGER, "age", a ->
|
||||
complete(String.format("Name: %s, age: %d", n, a))
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
final FormData formData = FormData.create(
|
||||
Pair.create("name", "Blippy"),
|
||||
Pair.create("age", "42"));
|
||||
final HttpRequest request =
|
||||
HttpRequest
|
||||
.POST("/")
|
||||
.withEntity(formData.toEntity());
|
||||
testRoute(route).run(request).assertEntity("Name: Blippy, age: 42");
|
||||
|
||||
//#simple
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormFieldValsUnmarshaling() {
|
||||
//#custom-unmarshal
|
||||
Unmarshaller<String, SampleId> SAMPLE_ID = StringUnmarshaller.sync(s -> new SampleId(Integer.valueOf(s)));
|
||||
|
||||
final Route route =
|
||||
formField(SAMPLE_ID, "id", sid ->
|
||||
complete(String.format("SampleId: %s", sid.id))
|
||||
);
|
||||
|
||||
// tests:
|
||||
final FormData formData = FormData.create(Pair.create("id", "1337"));
|
||||
final HttpRequest request =
|
||||
HttpRequest
|
||||
.POST("/")
|
||||
.withEntity(formData.toEntity());
|
||||
testRoute(route).run(request).assertEntity("SampleId: 1337");
|
||||
|
||||
//#custom-unmarshal
|
||||
}
|
||||
|
||||
static class SampleId {
|
||||
public final int id;
|
||||
|
||||
SampleId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
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.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
|
||||
public class HeaderRequestValsExampleTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testHeaderVals() {
|
||||
//#by-class
|
||||
|
||||
final Route route =
|
||||
extractHost(host ->
|
||||
complete(String.format("Host header was: %s", host))
|
||||
);
|
||||
|
||||
// tests:
|
||||
final HttpRequest request =
|
||||
HttpRequest
|
||||
.GET("http://akka.io/")
|
||||
.addHeader(Host.create("akka.io"));
|
||||
testRoute(route).run(request).assertEntity("Host header was: akka.io");
|
||||
|
||||
//#by-class
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderByName() {
|
||||
//#by-name
|
||||
|
||||
final Route route =
|
||||
// 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:
|
||||
final HttpRequest request =
|
||||
HttpRequest
|
||||
.GET("/")
|
||||
.addHeader(RawHeader.create("X-Fish-Name", "Blippy"));
|
||||
testRoute(route).run(request).assertEntity("The `X-Fish-Name` header's value was: Blippy");
|
||||
|
||||
//#by-name
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
//#binding-failure-high-level-example
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
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();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
// HttpApp.bindRoute expects a route being provided by HttpApp.createRoute
|
||||
final HighLevelServerExample app = new HighLevelServerExample();
|
||||
final Route route = app.createRoute();
|
||||
|
||||
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);
|
||||
|
||||
binding.exceptionally(failure -> {
|
||||
System.err.println("Something very bad happened! " + failure.getMessage());
|
||||
system.terminate();
|
||||
return null;
|
||||
});
|
||||
|
||||
system.terminate();
|
||||
}
|
||||
}
|
||||
//#binding-failure-high-level-example
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
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.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 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
|
||||
final HighLevelServerExample app = new HighLevelServerExample();
|
||||
|
||||
final Http http = Http.get(system);
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final Flow<HttpRequest, HttpResponse, NotUsed> routeFlow = app.createRoute().flow(system, materializer);
|
||||
final CompletionStage<ServerBinding> binding = http.bindAndHandle(routeFlow, ConnectHttp.toHost("localhost", 8080), materializer);
|
||||
|
||||
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
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
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.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.scaladsl.model.headers.Authorization;
|
||||
|
||||
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 Route route =
|
||||
authenticateBasic("My realm", this::authenticate, user ->
|
||||
complete("Hello " + user + "!")
|
||||
);
|
||||
|
||||
// tests:
|
||||
final HttpRequest okRequest =
|
||||
HttpRequest
|
||||
.GET("http://akka.io/")
|
||||
.addHeader(Host.create("akka.io"))
|
||||
.addHeader(Authorization.basic("randal", "correcthorsebatterystaple"));
|
||||
testRoute(route).run(okRequest).assertEntity("Hello randal!");
|
||||
|
||||
final HttpRequest badRequest =
|
||||
HttpRequest
|
||||
.GET("http://akka.io/")
|
||||
.addHeader(Host.create("akka.io"))
|
||||
.addHeader(Authorization.basic("randal", "123abc"));
|
||||
testRoute(route).run(badRequest).assertStatusCode(401);
|
||||
|
||||
//#basic-authenticator-java
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,328 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.Done;
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.http.javadsl.ConnectHttp;
|
||||
import akka.http.javadsl.Http;
|
||||
import akka.http.javadsl.IncomingConnection;
|
||||
import akka.http.javadsl.ServerBinding;
|
||||
import akka.http.javadsl.marshallers.jackson.Jackson;
|
||||
import akka.http.javadsl.model.*;
|
||||
import akka.http.javadsl.model.headers.Connection;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.unmarshalling.Unmarshaller;
|
||||
import akka.japi.function.Function;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.IOResult;
|
||||
import akka.stream.Materializer;
|
||||
import akka.stream.javadsl.FileIO;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Sink;
|
||||
import akka.stream.javadsl.Source;
|
||||
import akka.util.ByteString;
|
||||
import scala.concurrent.ExecutionContextExecutor;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static akka.http.javadsl.server.Directives.*;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HttpServerExampleDocTest {
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
//#consume-entity-directive
|
||||
class Bid {
|
||||
final String userId;
|
||||
final int bid;
|
||||
|
||||
Bid(String userId, int bid) {
|
||||
this.userId = userId;
|
||||
this.bid = bid;
|
||||
}
|
||||
}
|
||||
//#consume-entity-directive
|
||||
|
||||
void consumeEntityUsingEntityDirective() {
|
||||
//#consume-entity-directive
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ExecutionContextExecutor dispatcher = system.dispatcher();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final Unmarshaller<HttpEntity, Bid> asBid = Jackson.unmarshaller(Bid.class);
|
||||
|
||||
final Route s = path("bid", () ->
|
||||
put(() ->
|
||||
entity(asBid, bid ->
|
||||
// incoming entity is fully consumed and converted into a Bid
|
||||
complete("The bid was: " + bid)
|
||||
)
|
||||
)
|
||||
);
|
||||
//#consume-entity-directive
|
||||
}
|
||||
|
||||
void consumeEntityUsingRawDataBytes() {
|
||||
//#consume-raw-dataBytes
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ExecutionContextExecutor dispatcher = system.dispatcher();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final Route s =
|
||||
put(() ->
|
||||
path("lines", () ->
|
||||
withoutSizeLimit(() ->
|
||||
extractDataBytes(bytes -> {
|
||||
final CompletionStage<IOResult> res = bytes.runWith(FileIO.toPath(new File("/tmp/example.out").toPath()), materializer);
|
||||
|
||||
return onComplete(() -> res, ioResult ->
|
||||
// we only want to respond once the incoming data has been handled:
|
||||
complete("Finished writing data :" + ioResult));
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
//#consume-raw-dataBytes
|
||||
}
|
||||
|
||||
void discardEntityUsingRawBytes() {
|
||||
//#discard-discardEntityBytes
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ExecutionContextExecutor dispatcher = system.dispatcher();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final Route s =
|
||||
put(() ->
|
||||
path("lines", () ->
|
||||
withoutSizeLimit(() ->
|
||||
extractRequest(r -> {
|
||||
final CompletionStage<Done> res = r.discardEntityBytes(materializer).completionStage();
|
||||
|
||||
return onComplete(() -> res, done ->
|
||||
// we only want to respond once the incoming data has been handled:
|
||||
complete("Finished writing data :" + done));
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
//#discard-discardEntityBytes
|
||||
}
|
||||
|
||||
void discardEntityManuallyCloseConnections() {
|
||||
//#discard-close-connections
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final ExecutionContextExecutor dispatcher = system.dispatcher();
|
||||
final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
final Route s =
|
||||
put(() ->
|
||||
path("lines", () ->
|
||||
withoutSizeLimit(() ->
|
||||
extractDataBytes(bytes -> {
|
||||
// Closing connections, method 1 (eager):
|
||||
// we deem this request as illegal, and close the connection right away:
|
||||
bytes.runWith(Sink.cancelled(), materializer); // "brutally" closes the connection
|
||||
|
||||
// Closing connections, method 2 (graceful):
|
||||
// consider draining connection and replying with `Connection: Close` header
|
||||
// if you want the client to close after this request/reply cycle instead:
|
||||
return respondWithHeader(Connection.create("close"), () ->
|
||||
complete(StatusCodes.FORBIDDEN, "Not allowed!")
|
||||
);
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
//#discard-close-connections
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.actor.ActorSystem;
|
||||
import com.typesafe.sslconfig.akka.AkkaSSLConfig;
|
||||
import org.junit.Test;
|
||||
import org.scalatest.junit.JUnitSuite;
|
||||
|
||||
/* COMPILE ONLY TEST */
|
||||
public class HttpsServerExampleTest extends JUnitSuite {
|
||||
|
||||
@Test
|
||||
public void compileOnlySpec() throws Exception {
|
||||
// just making sure for it to be really compiled / run even if empty
|
||||
}
|
||||
|
||||
void sslConfigGet() {
|
||||
//#akka-ssl-config
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
|
||||
final AkkaSSLConfig sslConfig = AkkaSSLConfig.get(system);
|
||||
//#
|
||||
}
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.http.javadsl.common.CsvEntityStreamingSupport;
|
||||
import akka.http.javadsl.common.JsonEntityStreamingSupport;
|
||||
import akka.http.javadsl.marshallers.jackson.Jackson;
|
||||
import akka.http.javadsl.marshalling.Marshaller;
|
||||
import akka.http.javadsl.model.*;
|
||||
import akka.http.javadsl.model.headers.Accept;
|
||||
import akka.http.javadsl.server.*;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import akka.http.javadsl.unmarshalling.StringUnmarshallers;
|
||||
import akka.http.javadsl.common.EntityStreamingSupport;
|
||||
import akka.http.javadsl.unmarshalling.Unmarshaller;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Source;
|
||||
import akka.util.ByteString;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
public class JsonStreamingExamplesTest extends JUnitRouteTest {
|
||||
|
||||
//#routes
|
||||
final Route tweets() {
|
||||
//#formats
|
||||
final Unmarshaller<ByteString, JavaTweet> JavaTweets = Jackson.byteStringUnmarshaller(JavaTweet.class);
|
||||
//#formats
|
||||
|
||||
//#response-streaming
|
||||
|
||||
// Step 1: Enable JSON streaming
|
||||
// we're not using this in the example, but it's the simplest way to start:
|
||||
// The default rendering is a JSON array: `[el, el, el , ...]`
|
||||
final JsonEntityStreamingSupport jsonStreaming = EntityStreamingSupport.json();
|
||||
|
||||
// Step 1.1: Enable and customise how we'll render the JSON, as a compact array:
|
||||
final ByteString start = ByteString.fromString("[");
|
||||
final ByteString between = ByteString.fromString(",");
|
||||
final ByteString end = ByteString.fromString("]");
|
||||
final Flow<ByteString, ByteString, NotUsed> compactArrayRendering =
|
||||
Flow.of(ByteString.class).intersperse(start, between, end);
|
||||
|
||||
final JsonEntityStreamingSupport compactJsonSupport = EntityStreamingSupport.json()
|
||||
.withFramingRendererFlow(compactArrayRendering);
|
||||
|
||||
|
||||
// Step 2: implement the route
|
||||
final Route responseStreaming = path("tweets", () ->
|
||||
get(() ->
|
||||
parameter(StringUnmarshallers.INTEGER, "n", n -> {
|
||||
final Source<JavaTweet, NotUsed> tws =
|
||||
Source.repeat(new JavaTweet(12, "Hello World!")).take(n);
|
||||
|
||||
// Step 3: call complete* with your source, marshaller, and stream rendering mode
|
||||
return completeOKWithSource(tws, Jackson.marshaller(), compactJsonSupport);
|
||||
})
|
||||
)
|
||||
);
|
||||
//#response-streaming
|
||||
|
||||
//#incoming-request-streaming
|
||||
final Route incomingStreaming = path("tweets", () ->
|
||||
post(() ->
|
||||
extractMaterializer(mat -> {
|
||||
final JsonEntityStreamingSupport jsonSupport = EntityStreamingSupport.json();
|
||||
|
||||
return entityAsSourceOf(JavaTweets, jsonSupport, sourceOfTweets -> {
|
||||
final CompletionStage<Integer> tweetsCount = sourceOfTweets.runFold(0, (acc, tweet) -> acc + 1, mat);
|
||||
return onComplete(tweetsCount, c -> complete("Total number of tweets: " + c));
|
||||
});
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
//#incoming-request-streaming
|
||||
|
||||
return responseStreaming.orElse(incomingStreaming);
|
||||
}
|
||||
|
||||
final Route csvTweets() {
|
||||
//#csv-example
|
||||
final Marshaller<JavaTweet, ByteString> renderAsCsv =
|
||||
Marshaller.withFixedContentType(ContentTypes.TEXT_CSV_UTF8, t ->
|
||||
ByteString.fromString(t.getId() + "," + t.getMessage())
|
||||
);
|
||||
|
||||
final CsvEntityStreamingSupport compactJsonSupport = EntityStreamingSupport.csv();
|
||||
|
||||
final Route responseStreaming = path("tweets", () ->
|
||||
get(() ->
|
||||
parameter(StringUnmarshallers.INTEGER, "n", n -> {
|
||||
final Source<JavaTweet, NotUsed> tws =
|
||||
Source.repeat(new JavaTweet(12, "Hello World!")).take(n);
|
||||
return completeWithSource(tws, renderAsCsv, compactJsonSupport);
|
||||
})
|
||||
)
|
||||
);
|
||||
//#csv-example
|
||||
|
||||
return responseStreaming;
|
||||
}
|
||||
//#routes
|
||||
|
||||
@Test
|
||||
public void getTweetsTest() {
|
||||
//#response-streaming
|
||||
// tests:
|
||||
final TestRoute routes = testRoute(tweets());
|
||||
|
||||
// test happy path
|
||||
final Accept acceptApplication = Accept.create(MediaRanges.create(MediaTypes.APPLICATION_JSON));
|
||||
routes.run(HttpRequest.GET("/tweets?n=2").addHeader(acceptApplication))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("[{\"id\":12,\"message\":\"Hello World!\"},{\"id\":12,\"message\":\"Hello World!\"}]");
|
||||
|
||||
// test responses to potential errors
|
||||
final Accept acceptText = Accept.create(MediaRanges.ALL_TEXT);
|
||||
routes.run(HttpRequest.GET("/tweets?n=3").addHeader(acceptText))
|
||||
.assertStatusCode(StatusCodes.NOT_ACCEPTABLE) // 406
|
||||
.assertEntity("Resource representation is only available with these types:\napplication/json");
|
||||
//#response-streaming
|
||||
}
|
||||
|
||||
@Test
|
||||
public void csvExampleTweetsTest() {
|
||||
//#response-streaming
|
||||
// tests --------------------------------------------
|
||||
final TestRoute routes = testRoute(csvTweets());
|
||||
|
||||
// test happy path
|
||||
final Accept acceptCsv = Accept.create(MediaRanges.create(MediaTypes.TEXT_CSV));
|
||||
routes.run(HttpRequest.GET("/tweets?n=2").addHeader(acceptCsv))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("12,Hello World!\n" +
|
||||
"12,Hello World!");
|
||||
|
||||
// test responses to potential errors
|
||||
final Accept acceptText = Accept.create(MediaRanges.ALL_APPLICATION);
|
||||
routes.run(HttpRequest.GET("/tweets?n=3").addHeader(acceptText))
|
||||
.assertStatusCode(StatusCodes.NOT_ACCEPTABLE) // 406
|
||||
.assertEntity("Resource representation is only available with these types:\ntext/csv; charset=UTF-8");
|
||||
//#response-streaming
|
||||
}
|
||||
|
||||
//#models
|
||||
private static final class JavaTweet {
|
||||
private int id;
|
||||
private String message;
|
||||
|
||||
public JavaTweet(int id, String message) {
|
||||
this.id = id;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
//#models
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.headers.Host;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.scaladsl.model.headers.Authorization;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
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 Route route =
|
||||
authenticateOAuth2("My realm", this::authenticate, token ->
|
||||
complete("The secret token is: " + token)
|
||||
);
|
||||
|
||||
|
||||
// tests:
|
||||
final HttpRequest okRequest =
|
||||
HttpRequest
|
||||
.GET("http://akka.io/")
|
||||
.addHeader(Host.create("akka.io"))
|
||||
.addHeader(Authorization.oauth2("token"));
|
||||
testRoute(route).run(okRequest).assertEntity("The secret token is: token");
|
||||
|
||||
final HttpRequest badRequest =
|
||||
HttpRequest
|
||||
.GET("http://akka.io/")
|
||||
.addHeader(Host.create("akka.io"))
|
||||
.addHeader(Authorization.oauth2("wrong"));
|
||||
testRoute(route).run(badRequest).assertStatusCode(401);
|
||||
|
||||
//#oauth2-authenticator-java
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
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", () ->
|
||||
complete(StatusCodes.OK)
|
||||
);
|
||||
|
||||
// matches "/test", as well
|
||||
path(PathMatchers.segment("test"), () ->
|
||||
complete(StatusCodes.OK)
|
||||
);
|
||||
|
||||
// matches "/admin/user"
|
||||
path(PathMatchers.segment("admin")
|
||||
.slash("user"), () ->
|
||||
complete(StatusCodes.OK)
|
||||
);
|
||||
|
||||
// matches "/admin/user", as well
|
||||
pathPrefix("admin", () ->
|
||||
path("user", () ->
|
||||
complete(StatusCodes.OK)
|
||||
)
|
||||
);
|
||||
|
||||
// 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
|
||||
pathPrefix("admin", () ->
|
||||
path("user", () ->
|
||||
path(PathMatchers.integerSegment(), userId ->
|
||||
complete("Hello user " + userId)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// 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(() ->
|
||||
complete(StatusCodes.OK)
|
||||
),
|
||||
pathEnd(() ->
|
||||
complete(StatusCodes.OK)
|
||||
),
|
||||
path(PathMatchers.integerSegment(), userId ->
|
||||
complete("Hello user " + userId)
|
||||
)
|
||||
));
|
||||
//#path-examples
|
||||
}
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
//#websocket-example-using-core
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.http.javadsl.ConnectHttp;
|
||||
import akka.japi.Function;
|
||||
import akka.japi.JavaPartialFunction;
|
||||
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.Materializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Source;
|
||||
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.http.javadsl.Http;
|
||||
import akka.http.javadsl.ServerBinding;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.HttpResponse;
|
||||
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());
|
||||
|
||||
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
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ActorSystem system = ActorSystem.create();
|
||||
|
||||
try {
|
||||
final Materializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
//#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()));
|
||||
}
|
||||
}
|
||||
//#websocket-handler
|
||||
}
|
||||
//#websocket-example-using-core
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
public class WebSocketRoutingExample extends AllDirectives {
|
||||
|
||||
//#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, 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,893 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.dispatch.ExecutionContexts;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.http.javadsl.model.ContentTypes;
|
||||
import akka.http.javadsl.model.HttpEntities;
|
||||
import akka.http.javadsl.model.HttpEntity;
|
||||
import akka.http.javadsl.model.HttpMethods;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.HttpResponse;
|
||||
import akka.http.javadsl.model.ResponseEntity;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.model.headers.RawHeader;
|
||||
import akka.http.javadsl.model.headers.Server;
|
||||
import akka.http.javadsl.model.headers.ProductVersion;
|
||||
import akka.http.javadsl.settings.RoutingSettings;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.server.*;
|
||||
import akka.japi.pf.PFBuilder;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.ActorMaterializerSettings;
|
||||
import akka.stream.javadsl.FileIO;
|
||||
import akka.stream.javadsl.Sink;
|
||||
import akka.stream.javadsl.Source;
|
||||
import akka.util.ByteString;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import scala.concurrent.ExecutionContextExecutor;
|
||||
import scala.concurrent.duration.FiniteDuration;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class BasicDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testExtract() {
|
||||
//#extract
|
||||
final Route route = extract(
|
||||
ctx -> ctx.getRequest().getUri().toString().length(),
|
||||
len -> complete("The length of the request URI is " + len)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/abcdef"))
|
||||
.assertEntity("The length of the request URI is 25");
|
||||
//#extract
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractLog() {
|
||||
//#extractLog
|
||||
final Route route = extractLog(log -> {
|
||||
log.debug("I'm logging things in much detail..!");
|
||||
return complete("It's amazing!");
|
||||
});
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/abcdef"))
|
||||
.assertEntity("It's amazing!");
|
||||
//#extractLog
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMaterializer() {
|
||||
//#withMaterializer
|
||||
final ActorMaterializerSettings settings = ActorMaterializerSettings.create(system());
|
||||
final ActorMaterializer special = ActorMaterializer.create(settings, system(), "special");
|
||||
|
||||
final Route sample = path("sample", () ->
|
||||
extractMaterializer(mat ->
|
||||
onSuccess(() ->
|
||||
// explicitly use the materializer:
|
||||
Source.single("Materialized by " + mat.hashCode() + "!")
|
||||
.runWith(Sink.head(), mat), this::complete
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
final Route route = route(
|
||||
pathPrefix("special", () ->
|
||||
withMaterializer(special, () -> sample) // `special` materializer will be used
|
||||
),
|
||||
sample // default materializer will be used
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/sample"))
|
||||
.assertEntity("Materialized by " + materializer().hashCode()+ "!");
|
||||
testRoute(route).run(HttpRequest.GET("/special/sample"))
|
||||
.assertEntity("Materialized by " + special.hashCode()+ "!");
|
||||
//#withMaterializer
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractMaterializer() {
|
||||
//#extractMaterializer
|
||||
final Route route = path("sample", () ->
|
||||
extractMaterializer(mat ->
|
||||
onSuccess(() ->
|
||||
// explicitly use the materializer:
|
||||
Source.single("Materialized by " + mat.hashCode() + "!")
|
||||
.runWith(Sink.head(), mat), this::complete
|
||||
)
|
||||
)
|
||||
); // default materializer will be used
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/sample"))
|
||||
.assertEntity("Materialized by " + materializer().hashCode()+ "!");
|
||||
//#extractMaterializer
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithExecutionContext() {
|
||||
//#withExecutionContext
|
||||
|
||||
final ExecutionContextExecutor special =
|
||||
ExecutionContexts.fromExecutor(Executors.newFixedThreadPool(1));
|
||||
|
||||
final Route sample = path("sample", () ->
|
||||
extractExecutionContext(executor ->
|
||||
onSuccess(() ->
|
||||
CompletableFuture.supplyAsync(() ->
|
||||
"Run on " + executor.hashCode() + "!", executor
|
||||
), this::complete
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
final Route route = route(
|
||||
pathPrefix("special", () ->
|
||||
// `special` execution context will be used
|
||||
withExecutionContext(special, () -> sample)
|
||||
),
|
||||
sample // default execution context will be used
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/sample"))
|
||||
.assertEntity("Run on " + system().dispatcher().hashCode() + "!");
|
||||
testRoute(route).run(HttpRequest.GET("/special/sample"))
|
||||
.assertEntity("Run on " + special.hashCode() + "!");
|
||||
//#withExecutionContext
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractExecutionContext() {
|
||||
//#extractExecutionContext
|
||||
final Route route = path("sample", () ->
|
||||
extractExecutionContext(executor ->
|
||||
onSuccess(() ->
|
||||
CompletableFuture.supplyAsync(
|
||||
// uses the `executor` ExecutionContext
|
||||
() -> "Run on " + executor.hashCode() + "!", executor
|
||||
), str -> complete(str)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
//tests:
|
||||
testRoute(route).run(HttpRequest.GET("/sample"))
|
||||
.assertEntity("Run on " + system().dispatcher().hashCode() + "!");
|
||||
//#extractExecutionContext
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithLog() {
|
||||
//#withLog
|
||||
final LoggingAdapter special = Logging.getLogger(system(), "SpecialRoutes");
|
||||
|
||||
final Route sample = path("sample", () ->
|
||||
extractLog(log -> {
|
||||
final String msg = "Logging using " + log + "!";
|
||||
log.debug(msg);
|
||||
return complete(msg);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
final Route route = route(
|
||||
pathPrefix("special", () ->
|
||||
withLog(special, () -> sample)
|
||||
),
|
||||
sample
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/sample"))
|
||||
.assertEntity("Logging using " + system().log() + "!");
|
||||
testRoute(route).run(HttpRequest.GET("/special/sample"))
|
||||
.assertEntity("Logging using " + special + "!");
|
||||
//#withLog
|
||||
}
|
||||
|
||||
@Ignore("Ignore compile-only test")
|
||||
@Test
|
||||
public void testWithSettings() {
|
||||
//#withSettings
|
||||
final RoutingSettings special =
|
||||
RoutingSettings
|
||||
.create(system().settings().config())
|
||||
.withFileIODispatcher("special-io-dispatcher");
|
||||
|
||||
final Route sample = path("sample", () -> {
|
||||
// internally uses the configured fileIODispatcher:
|
||||
// ContentTypes.APPLICATION_JSON, source
|
||||
final Source<ByteString, Object> source =
|
||||
FileIO.fromPath(Paths.get("example.json"))
|
||||
.mapMaterializedValue(completionStage -> (Object) completionStage);
|
||||
return complete(
|
||||
HttpResponse.create()
|
||||
.withEntity(HttpEntities.create(ContentTypes.APPLICATION_JSON, source))
|
||||
);
|
||||
});
|
||||
|
||||
final Route route = get(() ->
|
||||
route(
|
||||
pathPrefix("special", () ->
|
||||
// `special` file-io-dispatcher will be used to read the file
|
||||
withSettings(special, () -> sample)
|
||||
),
|
||||
sample // default file-io-dispatcher will be used to read the file
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/special/sample"))
|
||||
.assertEntity("{}");
|
||||
testRoute(route).run(HttpRequest.GET("/sample"))
|
||||
.assertEntity("{}");
|
||||
//#withSettings
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapResponse() {
|
||||
//#mapResponse
|
||||
final Route route = mapResponse(
|
||||
response -> response.withStatus(StatusCodes.BAD_GATEWAY),
|
||||
() -> complete("abc")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/abcdef?ghi=12"))
|
||||
.assertStatusCode(StatusCodes.BAD_GATEWAY);
|
||||
//#mapResponse
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapResponseAdvanced() {
|
||||
//#mapResponse-advanced
|
||||
class ApiRoute {
|
||||
|
||||
private final ActorSystem system;
|
||||
|
||||
private final LoggingAdapter log;
|
||||
|
||||
private final HttpEntity nullJsonEntity =
|
||||
HttpEntities.create(ContentTypes.APPLICATION_JSON, "{}");
|
||||
|
||||
public ApiRoute(ActorSystem system) {
|
||||
this.system = system;
|
||||
this.log = Logging.getLogger(system, "ApiRoutes");
|
||||
}
|
||||
|
||||
private HttpResponse nonSuccessToEmptyJsonEntity(HttpResponse response) {
|
||||
if (response.status().isSuccess()) {
|
||||
return response;
|
||||
} else {
|
||||
log.warning(
|
||||
"Dropping response entity since response status code was: " + response.status());
|
||||
return response.withEntity((ResponseEntity) nullJsonEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/** Wrapper for all of our JSON API routes */
|
||||
private Route apiRoute(Supplier<Route> innerRoutes) {
|
||||
return mapResponse(this::nonSuccessToEmptyJsonEntity, innerRoutes);
|
||||
}
|
||||
}
|
||||
|
||||
final ApiRoute api = new ApiRoute(system());
|
||||
|
||||
final Route route = api.apiRoute(() ->
|
||||
get(() -> complete(StatusCodes.INTERNAL_SERVER_ERROR))
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("{}");
|
||||
//#mapResponse-advanced
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapRouteResult() {
|
||||
//#mapRouteResult
|
||||
// this directive is a joke, don't do that :-)
|
||||
final Route route = mapRouteResult(r -> {
|
||||
if (r instanceof Complete) {
|
||||
final HttpResponse response = ((Complete) r).getResponse();
|
||||
return RouteResults.complete(response.withStatus(200));
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}, () -> complete(StatusCodes.ACCEPTED));
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
//#mapRouteResult
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapRouteResultFuture() {
|
||||
//#mapRouteResultFuture
|
||||
final Route route = mapRouteResultFuture(cr ->
|
||||
cr.exceptionally(t -> {
|
||||
if (t instanceof IllegalArgumentException) {
|
||||
return RouteResults.complete(
|
||||
HttpResponse.create().withStatus(StatusCodes.INTERNAL_SERVER_ERROR));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}).thenApply(rr -> {
|
||||
if (rr instanceof Complete) {
|
||||
final HttpResponse res = ((Complete) rr).getResponse();
|
||||
return RouteResults.complete(
|
||||
res.addHeader(Server.create(ProductVersion.create("MyServer", "1.0"))));
|
||||
} else {
|
||||
return rr;
|
||||
}
|
||||
}), () -> complete("Hello world!"));
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertHeaderExists(Server.create(ProductVersion.create("MyServer", "1.0")));
|
||||
//#mapRouteResultFuture
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapResponseEntity() {
|
||||
//#mapResponseEntity
|
||||
final Function<ResponseEntity, ResponseEntity> prefixEntity = entity -> {
|
||||
if (entity instanceof HttpEntity.Strict) {
|
||||
final HttpEntity.Strict strict = (HttpEntity.Strict) entity;
|
||||
return HttpEntities.create(
|
||||
strict.getContentType(),
|
||||
ByteString.fromString("test").concat(strict.getData()));
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected entity type");
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = mapResponseEntity(prefixEntity, () -> complete("abc"));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("testabc");
|
||||
//#mapResponseEntity
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapResponseHeaders() {
|
||||
//#mapResponseHeaders
|
||||
// adds all request headers to the response
|
||||
final Route echoRequestHeaders = extract(
|
||||
ctx -> ctx.getRequest().getHeaders(),
|
||||
headers -> respondWithHeaders(headers, () -> complete("test"))
|
||||
);
|
||||
|
||||
final Route route = mapResponseHeaders(headers -> {
|
||||
headers.removeIf(header -> header.lowercaseName().equals("id"));
|
||||
return headers;
|
||||
}, () -> echoRequestHeaders);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeaders(
|
||||
Arrays.asList(RawHeader.create("id", "12345"),RawHeader.create("id2", "67890"))))
|
||||
.assertHeaderKindNotExists("id")
|
||||
.assertHeaderExists("id2", "67890");
|
||||
//#mapResponseHeaders
|
||||
}
|
||||
|
||||
@Ignore("Not implemented yet")
|
||||
@Test
|
||||
public void testMapInnerRoute() {
|
||||
//#mapInnerRoute
|
||||
// TODO: implement mapInnerRoute
|
||||
//#mapInnerRoute
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapRejections() {
|
||||
//#mapRejections
|
||||
// ignore any rejections and replace them by AuthorizationFailedRejection
|
||||
final Route route = mapRejections(
|
||||
rejections -> Collections.singletonList((Rejection) Rejections.authorizationFailed()),
|
||||
() -> path("abc", () -> complete("abc"))
|
||||
);
|
||||
|
||||
// tests:
|
||||
runRouteUnSealed(route, HttpRequest.GET("/"))
|
||||
.assertRejections(Rejections.authorizationFailed());
|
||||
testRoute(route).run(HttpRequest.GET("/abc"))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
//#mapRejections
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoverRejections() {
|
||||
//#recoverRejections
|
||||
final Function<Optional<ProvidedCredentials>, Optional<Object>> neverAuth =
|
||||
creds -> Optional.empty();
|
||||
final Function<Optional<ProvidedCredentials>, Optional<Object>> alwaysAuth =
|
||||
creds -> Optional.of("id");
|
||||
|
||||
final Route originalRoute = pathPrefix("auth", () ->
|
||||
route(
|
||||
path("never", () ->
|
||||
authenticateBasic("my-realm", neverAuth, obj -> complete("Welcome to the bat-cave!"))
|
||||
),
|
||||
path("always", () ->
|
||||
authenticateBasic("my-realm", alwaysAuth, obj -> complete("Welcome to the secret place!"))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
final Function<Iterable<Rejection>, Boolean> existsAuthenticationFailedRejection =
|
||||
rejections ->
|
||||
StreamSupport.stream(rejections.spliterator(), false)
|
||||
.anyMatch(r -> r instanceof AuthenticationFailedRejection);
|
||||
|
||||
final Route route = recoverRejections(rejections -> {
|
||||
if (existsAuthenticationFailedRejection.apply(rejections)) {
|
||||
return RouteResults.complete(
|
||||
HttpResponse.create().withEntity("Nothing to see here, move along."));
|
||||
} else if (!rejections.iterator().hasNext()) { // see "Empty Rejections" for more details
|
||||
return RouteResults.complete(
|
||||
HttpResponse.create().withStatus(StatusCodes.NOT_FOUND)
|
||||
.withEntity("Literally nothing to see here."));
|
||||
} else {
|
||||
return RouteResults.rejected(rejections);
|
||||
}
|
||||
}, () -> originalRoute);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/auth/never"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("Nothing to see here, move along.");
|
||||
testRoute(route).run(HttpRequest.GET("/auth/always"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("Welcome to the secret place!");
|
||||
testRoute(route).run(HttpRequest.GET("/auth/does_not_exist"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND)
|
||||
.assertEntity("Literally nothing to see here.");
|
||||
//#recoverRejections
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoverRejectionsWith() {
|
||||
//#recoverRejectionsWith
|
||||
final Function<Optional<ProvidedCredentials>, Optional<Object>> neverAuth =
|
||||
creds -> Optional.empty();
|
||||
|
||||
final Route originalRoute = pathPrefix("auth", () ->
|
||||
path("never", () ->
|
||||
authenticateBasic("my-realm", neverAuth, obj -> complete("Welcome to the bat-cave!"))
|
||||
)
|
||||
);
|
||||
|
||||
final Function<Iterable<Rejection>, Boolean> existsAuthenticationFailedRejection =
|
||||
rejections ->
|
||||
StreamSupport.stream(rejections.spliterator(), false)
|
||||
.anyMatch(r -> r instanceof AuthenticationFailedRejection);
|
||||
|
||||
final Route route = recoverRejectionsWith(
|
||||
rejections -> CompletableFuture.supplyAsync(() -> {
|
||||
if (existsAuthenticationFailedRejection.apply(rejections)) {
|
||||
return RouteResults.complete(
|
||||
HttpResponse.create().withEntity("Nothing to see here, move along."));
|
||||
} else {
|
||||
return RouteResults.rejected(rejections);
|
||||
}
|
||||
}), () -> originalRoute);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/auth/never"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("Nothing to see here, move along.");
|
||||
//#recoverRejectionsWith
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapRequest() {
|
||||
//#mapRequest
|
||||
final Route route = mapRequest(req ->
|
||||
req.withMethod(HttpMethods.POST), () ->
|
||||
extractRequest(req -> complete("The request method was " + req.method().name()))
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("The request method was POST");
|
||||
//#mapRequest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapRequestContext() {
|
||||
//#mapRequestContext
|
||||
final Route route = mapRequestContext(ctx ->
|
||||
ctx.withRequest(HttpRequest.create().withMethod(HttpMethods.POST)), () ->
|
||||
extractRequest(req -> complete(req.method().value()))
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/abc/def/ghi"))
|
||||
.assertEntity("POST");
|
||||
//#mapRequestContext
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapRouteResult0() {
|
||||
//#mapRouteResult
|
||||
final Route route = mapRouteResult(rr -> {
|
||||
final Iterable<Rejection> rejections = Collections.singletonList(Rejections.authorizationFailed());
|
||||
return RouteResults.rejected(rejections);
|
||||
}, () -> complete("abc"));
|
||||
|
||||
// tests:
|
||||
runRouteUnSealed(route, HttpRequest.GET("/"))
|
||||
.assertRejections(Rejections.authorizationFailed());
|
||||
//#mapRouteResult
|
||||
}
|
||||
|
||||
public static final class MyCustomRejection implements CustomRejection {}
|
||||
|
||||
@Test
|
||||
public void testMapRouteResultPF() {
|
||||
//#mapRouteResultPF
|
||||
final Route route = mapRouteResultPF(
|
||||
new PFBuilder<RouteResult, RouteResult>()
|
||||
.match(Rejected.class, rejected -> {
|
||||
final Iterable<Rejection> rejections =
|
||||
Collections.singletonList(Rejections.authorizationFailed());
|
||||
return RouteResults.rejected(rejections);
|
||||
}).build(), () -> reject(new MyCustomRejection()));
|
||||
|
||||
// tests:
|
||||
runRouteUnSealed(route, HttpRequest.GET("/"))
|
||||
.assertRejections(Rejections.authorizationFailed());
|
||||
//#mapRouteResultPF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapRouteResultWithPF() {
|
||||
//#mapRouteResultWithPF
|
||||
final Route route = mapRouteResultWithPF(
|
||||
new PFBuilder<RouteResult, CompletionStage<RouteResult>>()
|
||||
.match(Rejected.class, rejected -> CompletableFuture.supplyAsync(() -> {
|
||||
final Iterable<Rejection> rejections =
|
||||
Collections.singletonList(Rejections.authorizationFailed());
|
||||
return RouteResults.rejected(rejections);
|
||||
})
|
||||
).build(), () -> reject(new MyCustomRejection()));
|
||||
|
||||
// tests:
|
||||
runRouteUnSealed(route, HttpRequest.GET("/"))
|
||||
.assertRejections(Rejections.authorizationFailed());
|
||||
//#mapRouteResultWithPF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapRouteResultWith() {
|
||||
//#mapRouteResultWith
|
||||
final Route route = mapRouteResultWith(rr -> CompletableFuture.supplyAsync(() -> {
|
||||
if (rr instanceof Rejected) {
|
||||
final Iterable<Rejection> rejections =
|
||||
Collections.singletonList(Rejections.authorizationFailed());
|
||||
return RouteResults.rejected(rejections);
|
||||
} else {
|
||||
return rr;
|
||||
}
|
||||
}), () -> reject(new MyCustomRejection()));
|
||||
|
||||
// tests:
|
||||
runRouteUnSealed(route, HttpRequest.GET("/"))
|
||||
.assertRejections(Rejections.authorizationFailed());
|
||||
//#mapRouteResultWith
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPass() {
|
||||
//#pass
|
||||
final Route route = pass(() -> complete("abc"));
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("abc");
|
||||
//#pass
|
||||
}
|
||||
|
||||
private Route providePrefixedStringRoute(String value) {
|
||||
return provide("prefix:" + value, this::complete);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvide() {
|
||||
//#provide
|
||||
final Route route = providePrefixedStringRoute("test");
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("prefix:test");
|
||||
//#provide
|
||||
}
|
||||
|
||||
@Ignore("Test failed")
|
||||
@Test
|
||||
public void testCancelRejections() {
|
||||
//#cancelRejections
|
||||
final Predicate<Rejection> isMethodRejection = p -> p instanceof MethodRejection;
|
||||
final Route route = cancelRejections(
|
||||
isMethodRejection, () -> post(() -> complete("Result"))
|
||||
);
|
||||
|
||||
// tests:
|
||||
runRouteUnSealed(route, HttpRequest.GET("/"))
|
||||
.assertRejections();
|
||||
//#cancelRejections
|
||||
}
|
||||
|
||||
@Ignore("Test failed")
|
||||
@Test
|
||||
public void testCancelRejection() {
|
||||
//#cancelRejection
|
||||
final Route route = cancelRejection(Rejections.method(HttpMethods.POST), () ->
|
||||
post(() -> complete("Result"))
|
||||
);
|
||||
|
||||
// tests:
|
||||
runRouteUnSealed(route, HttpRequest.GET("/"))
|
||||
.assertRejections();
|
||||
//#cancelRejection
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractRequest() {
|
||||
//#extractRequest
|
||||
final Route route = extractRequest(request ->
|
||||
complete("Request method is " + request.method().name() +
|
||||
" and content-type is " + request.entity().getContentType())
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity("text"))
|
||||
.assertEntity("Request method is POST and content-type is text/plain; charset=UTF-8");
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("Request method is GET and content-type is none/none");
|
||||
//#extractRequest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractSettings() {
|
||||
//#extractSettings
|
||||
final Route route = extractSettings(settings ->
|
||||
complete("RoutingSettings.renderVanityFooter = " + settings.getRenderVanityFooter())
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("RoutingSettings.renderVanityFooter = true");
|
||||
//#extractSettings
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSettings() {
|
||||
//#mapSettings
|
||||
final Route route = mapSettings(settings ->
|
||||
settings.withFileGetConditional(false), () ->
|
||||
extractSettings(settings ->
|
||||
complete("RoutingSettings.fileGetConditional = " + settings.getFileGetConditional())
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("RoutingSettings.fileGetConditional = false");
|
||||
//#mapSettings
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractRequestContext() {
|
||||
//#extractRequestContext
|
||||
final Route route = extractRequestContext(ctx -> {
|
||||
ctx.getLog().debug("Using access to additional context availablethings, like the logger.");
|
||||
final HttpRequest request = ctx.getRequest();
|
||||
return complete("Request method is " + request.method().name() +
|
||||
" and content-type is " + request.entity().getContentType());
|
||||
});
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity("text"))
|
||||
.assertEntity("Request method is POST and content-type is text/plain; charset=UTF-8");
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("Request method is GET and content-type is none/none");
|
||||
//#extractRequestContext
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractUri() {
|
||||
//#extractUri
|
||||
final Route route = extractUri(uri ->
|
||||
complete("Full URI: " + uri)
|
||||
);
|
||||
|
||||
// tests:
|
||||
// tests are executed with the host assumed to be "example.com"
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("Full URI: http://example.com/");
|
||||
testRoute(route).run(HttpRequest.GET("/test"))
|
||||
.assertEntity("Full URI: http://example.com/test");
|
||||
//#extractUri
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapUnmatchedPath() {
|
||||
//#mapUnmatchedPath
|
||||
final Function<String, String> ignore456 = path -> {
|
||||
int slashPos = path.indexOf("/");
|
||||
if (slashPos != -1) {
|
||||
String head = path.substring(0, slashPos);
|
||||
String tail = path.substring(slashPos);
|
||||
if (head.length() <= 3) {
|
||||
return tail;
|
||||
} else {
|
||||
return path.substring(3);
|
||||
}
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = pathPrefix("123", () ->
|
||||
mapUnmatchedPath(ignore456, () ->
|
||||
path("abc", () ->
|
||||
complete("Content")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/123/abc"))
|
||||
.assertEntity("Content");
|
||||
testRoute(route).run(HttpRequest.GET("/123456/abc"))
|
||||
.assertEntity("Content");
|
||||
//#mapUnmatchedPath
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractUnmatchedPath() {
|
||||
//#extractUnmatchedPath
|
||||
final Route route = pathPrefix("abc", () ->
|
||||
extractUnmatchedPath(remaining ->
|
||||
complete("Unmatched: '" + remaining + "'")
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/abc"))
|
||||
.assertEntity("Unmatched: ''");
|
||||
testRoute(route).run(HttpRequest.GET("/abc/456"))
|
||||
.assertEntity("Unmatched: '/456'");
|
||||
//#extractUnmatchedPath
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractRequestEntity() {
|
||||
//#extractRequestEntity
|
||||
final Route route = extractRequestEntity(entity ->
|
||||
complete("Request entity content-type is " + entity.getContentType())
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(
|
||||
HttpRequest.POST("/abc")
|
||||
.withEntity(HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, "req"))
|
||||
).assertEntity("Request entity content-type is text/plain; charset=UTF-8");
|
||||
//#extractRequestEntity
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractDataBytes() {
|
||||
//#extractDataBytes
|
||||
final Route route = extractDataBytes(data -> {
|
||||
final CompletionStage<Integer> sum = data.runFold(0, (acc, i) ->
|
||||
acc + Integer.valueOf(i.utf8String()), materializer());
|
||||
return onSuccess(() -> sum, s ->
|
||||
complete(HttpResponse.create().withEntity(HttpEntities.create(s.toString()))));
|
||||
});
|
||||
|
||||
// tests:
|
||||
final Iterator iterator = Arrays.asList(
|
||||
ByteString.fromString("1"),
|
||||
ByteString.fromString("2"),
|
||||
ByteString.fromString("3")).iterator();
|
||||
final Source<ByteString, NotUsed> dataBytes = Source.fromIterator(() -> iterator);
|
||||
|
||||
testRoute(route).run(
|
||||
HttpRequest.POST("abc")
|
||||
.withEntity(HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, dataBytes))
|
||||
).assertEntity("6");
|
||||
//#extractDataBytes
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractStrictEntity() {
|
||||
//#extractStrictEntity
|
||||
final FiniteDuration timeout = FiniteDuration.create(3, TimeUnit.SECONDS);
|
||||
final Route route = extractStrictEntity(timeout, strict ->
|
||||
complete(strict.getData().utf8String())
|
||||
);
|
||||
|
||||
// tests:
|
||||
final Iterator iterator = Arrays.asList(
|
||||
ByteString.fromString("1"),
|
||||
ByteString.fromString("2"),
|
||||
ByteString.fromString("3")).iterator();
|
||||
final Source<ByteString, NotUsed> dataBytes = Source.fromIterator(() -> iterator);
|
||||
testRoute(route).run(
|
||||
HttpRequest.POST("/")
|
||||
.withEntity(HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, dataBytes))
|
||||
).assertEntity("123");
|
||||
//#extractStrictEntity
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToStrictEntity() {
|
||||
//#toStrictEntity
|
||||
final FiniteDuration timeout = FiniteDuration.create(3, TimeUnit.SECONDS);
|
||||
final Route route = toStrictEntity(timeout, () ->
|
||||
extractRequest(req -> {
|
||||
if (req.entity() instanceof HttpEntity.Strict) {
|
||||
final HttpEntity.Strict strict = (HttpEntity.Strict)req.entity();
|
||||
return complete("Request entity is strict, data=" + strict.getData().utf8String());
|
||||
} else {
|
||||
return complete("Ooops, request entity is not strict!");
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// tests:
|
||||
final Iterator iterator = Arrays.asList(
|
||||
ByteString.fromString("1"),
|
||||
ByteString.fromString("2"),
|
||||
ByteString.fromString("3")).iterator();
|
||||
final Source<ByteString, NotUsed> dataBytes = Source.fromIterator(() -> iterator);
|
||||
testRoute(route).run(
|
||||
HttpRequest.POST("/")
|
||||
.withEntity(HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, dataBytes))
|
||||
).assertEntity("Request entity is strict, data=123");
|
||||
//#toStrictEntity
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractActorSystem() {
|
||||
//#extractActorSystem
|
||||
final Route route = extractActorSystem(actorSystem ->
|
||||
complete("Actor System extracted, hash=" + actorSystem.hashCode())
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("Actor System extracted, hash=" + system().hashCode());
|
||||
//#extractActorSystem
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.headers.AcceptEncoding;
|
||||
import akka.http.javadsl.model.headers.ContentEncoding;
|
||||
import akka.http.javadsl.model.headers.HttpEncodings;
|
||||
import akka.http.javadsl.coding.Coder;
|
||||
import akka.http.javadsl.server.Rejections;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.util.ByteString;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static akka.http.javadsl.unmarshalling.Unmarshaller.entityToString;
|
||||
|
||||
public class CodingDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testResponseEncodingAccepted() {
|
||||
//#responseEncodingAccepted
|
||||
final Route route = responseEncodingAccepted(HttpEncodings.GZIP, () ->
|
||||
complete("content")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("content");
|
||||
runRouteUnSealed(route,
|
||||
HttpRequest.GET("/")
|
||||
.addHeader(AcceptEncoding.create(HttpEncodings.DEFLATE)))
|
||||
.assertRejections(Rejections.unacceptedResponseEncoding(HttpEncodings.GZIP));
|
||||
//#responseEncodingAccepted
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeResponse() {
|
||||
//#encodeResponse
|
||||
final Route route = encodeResponse(() -> complete("content"));
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(
|
||||
HttpRequest.GET("/")
|
||||
.addHeader(AcceptEncoding.create(HttpEncodings.GZIP))
|
||||
.addHeader(AcceptEncoding.create(HttpEncodings.DEFLATE))
|
||||
).assertHeaderExists(ContentEncoding.create(HttpEncodings.GZIP));
|
||||
|
||||
testRoute(route).run(
|
||||
HttpRequest.GET("/")
|
||||
.addHeader(AcceptEncoding.create(HttpEncodings.DEFLATE))
|
||||
).assertHeaderExists(ContentEncoding.create(HttpEncodings.DEFLATE));
|
||||
|
||||
// This case failed!
|
||||
// testRoute(route).run(
|
||||
// HttpRequest.GET("/")
|
||||
// .addHeader(AcceptEncoding.create(HttpEncodings.IDENTITY))
|
||||
// ).assertHeaderExists(ContentEncoding.create(HttpEncodings.IDENTITY));
|
||||
|
||||
//#encodeResponse
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeResponseWith() {
|
||||
//#encodeResponseWith
|
||||
final Route route = encodeResponseWith(
|
||||
Collections.singletonList(Coder.Gzip),
|
||||
() -> complete("content")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertHeaderExists(ContentEncoding.create(HttpEncodings.GZIP));
|
||||
|
||||
testRoute(route).run(
|
||||
HttpRequest.GET("/")
|
||||
.addHeader(AcceptEncoding.create(HttpEncodings.GZIP))
|
||||
.addHeader(AcceptEncoding.create(HttpEncodings.DEFLATE))
|
||||
).assertHeaderExists(ContentEncoding.create(HttpEncodings.GZIP));
|
||||
|
||||
runRouteUnSealed(route,
|
||||
HttpRequest.GET("/")
|
||||
.addHeader(AcceptEncoding.create(HttpEncodings.DEFLATE))
|
||||
).assertRejections(Rejections.unacceptedResponseEncoding(HttpEncodings.GZIP));
|
||||
|
||||
runRouteUnSealed(route,
|
||||
HttpRequest.GET("/")
|
||||
.addHeader(AcceptEncoding.create(HttpEncodings.IDENTITY))
|
||||
).assertRejections(Rejections.unacceptedResponseEncoding(HttpEncodings.GZIP));
|
||||
//#encodeResponseWith
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecodeRequest() {
|
||||
//#decodeRequest
|
||||
final ByteString helloGzipped = Coder.Gzip.encode(ByteString.fromString("Hello"));
|
||||
final ByteString helloDeflated = Coder.Deflate.encode(ByteString.fromString("Hello"));
|
||||
|
||||
final Route route = decodeRequest(() ->
|
||||
entity(entityToString(), content ->
|
||||
complete("Request content: '" + content + "'")
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(
|
||||
HttpRequest.POST("/").withEntity(helloGzipped)
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.GZIP)))
|
||||
.assertEntity("Request content: 'Hello'");
|
||||
|
||||
testRoute(route).run(
|
||||
HttpRequest.POST("/").withEntity(helloDeflated)
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.DEFLATE)))
|
||||
.assertEntity("Request content: 'Hello'");
|
||||
|
||||
testRoute(route).run(
|
||||
HttpRequest.POST("/").withEntity("hello uncompressed")
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.IDENTITY)))
|
||||
.assertEntity( "Request content: 'hello uncompressed'");
|
||||
//#decodeRequest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecodeRequestWith() {
|
||||
//#decodeRequestWith
|
||||
final ByteString helloGzipped = Coder.Gzip.encode(ByteString.fromString("Hello"));
|
||||
final ByteString helloDeflated = Coder.Deflate.encode(ByteString.fromString("Hello"));
|
||||
|
||||
final Route route = decodeRequestWith(Coder.Gzip, () ->
|
||||
entity(entityToString(), content ->
|
||||
complete("Request content: '" + content + "'")
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(
|
||||
HttpRequest.POST("/").withEntity(helloGzipped)
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.GZIP)))
|
||||
.assertEntity("Request content: 'Hello'");
|
||||
|
||||
runRouteUnSealed(route,
|
||||
HttpRequest.POST("/").withEntity(helloDeflated)
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.DEFLATE)))
|
||||
.assertRejections(Rejections.unsupportedRequestEncoding(HttpEncodings.GZIP));
|
||||
|
||||
runRouteUnSealed(route,
|
||||
HttpRequest.POST("/").withEntity("hello")
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.IDENTITY)))
|
||||
.assertRejections(Rejections.unsupportedRequestEncoding(HttpEncodings.GZIP));
|
||||
//#decodeRequestWith
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpHeader;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.headers.Cookie;
|
||||
import akka.http.javadsl.model.headers.HttpCookie;
|
||||
import akka.http.javadsl.model.headers.SetCookie;
|
||||
import akka.http.javadsl.server.Rejections;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.scaladsl.model.DateTime;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
|
||||
public class CookieDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testCookie() {
|
||||
//#cookie
|
||||
final Route route = cookie("userName", nameCookie ->
|
||||
complete("The logged in user is '" + nameCookie.value() + "'")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Cookie.create("userName", "paul")))
|
||||
.assertEntity("The logged in user is 'paul'");
|
||||
// missing cookie
|
||||
runRouteUnSealed(route, HttpRequest.GET("/"))
|
||||
.assertRejections(Rejections.missingCookie("userName"));
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("Request is missing required cookie 'userName'");
|
||||
//#cookie
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalCookie() {
|
||||
//#optionalCookie
|
||||
final Route route = optionalCookie("userName", optNameCookie -> {
|
||||
if (optNameCookie.isPresent()) {
|
||||
return complete("The logged in user is '" + optNameCookie.get().value() + "'");
|
||||
} else {
|
||||
return complete("No user logged in");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Cookie.create("userName", "paul")))
|
||||
.assertEntity("The logged in user is 'paul'");
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("No user logged in");
|
||||
//#optionalCookie
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteCookie() {
|
||||
//#deleteCookie
|
||||
final Route route = deleteCookie("userName", () ->
|
||||
complete("The user was logged out")
|
||||
);
|
||||
|
||||
// tests:
|
||||
final HttpHeader expected = SetCookie.create(
|
||||
HttpCookie.create(
|
||||
"userName",
|
||||
"deleted",
|
||||
Optional.of(DateTime.MinValue()),
|
||||
OptionalLong.empty(),
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
Optional.empty()));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("The user was logged out")
|
||||
.assertHeaderExists(expected);
|
||||
//#deleteCookie
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCookie() {
|
||||
//#setCookie
|
||||
final Route route = setCookie(HttpCookie.create("userName", "paul"), () ->
|
||||
complete("The user was logged in")
|
||||
);
|
||||
|
||||
// tests:
|
||||
final HttpHeader expected = SetCookie.create(HttpCookie.create("userName", "paul"));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("The user was logged in")
|
||||
.assertHeaderExists(expected);
|
||||
//#setCookie
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.event.NoLogging;
|
||||
import akka.http.javadsl.ConnectHttp;
|
||||
import akka.http.javadsl.Http;
|
||||
import akka.http.javadsl.ServerBinding;
|
||||
import akka.http.javadsl.model.*;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.settings.ParserSettings;
|
||||
import akka.http.javadsl.settings.ServerSettings;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.stream.Materializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static akka.http.javadsl.model.HttpProtocols.HTTP_1_0;
|
||||
import static akka.http.javadsl.model.RequestEntityAcceptances.Expected;
|
||||
|
||||
public class CustomHttpMethodExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testComposition() throws InterruptedException, ExecutionException {
|
||||
ActorSystem system = system();
|
||||
Materializer materializer = materializer();
|
||||
LoggingAdapter loggingAdapter = NoLogging.getInstance();
|
||||
|
||||
int port = 9090;
|
||||
String host = "127.0.0.1";
|
||||
|
||||
//#customHttpMethod
|
||||
HttpMethod BOLT =
|
||||
HttpMethods.createCustom("BOLT", false, true, Expected);
|
||||
final ParserSettings parserSettings =
|
||||
ParserSettings.create(system).withCustomMethods(BOLT);
|
||||
final ServerSettings serverSettings =
|
||||
ServerSettings.create(system).withParserSettings(parserSettings);
|
||||
|
||||
final Route routes = route(
|
||||
extractMethod( method ->
|
||||
complete( "This is a " + method.name() + " request.")
|
||||
)
|
||||
);
|
||||
final Flow<HttpRequest, HttpResponse, NotUsed> handler = routes.flow(system, materializer);
|
||||
final Http http = Http.get(system);
|
||||
final CompletionStage<ServerBinding> binding =
|
||||
http.bindAndHandle(
|
||||
handler,
|
||||
ConnectHttp.toHost(host, port),
|
||||
serverSettings,
|
||||
loggingAdapter,
|
||||
materializer);
|
||||
|
||||
HttpRequest request = HttpRequest.create()
|
||||
.withUri("http://" + host + ":" + Integer.toString(port))
|
||||
.withMethod(BOLT)
|
||||
.withProtocol(HTTP_1_0);
|
||||
|
||||
CompletionStage<HttpResponse> response = http.singleRequest(request, materializer);
|
||||
//#customHttpMethod
|
||||
|
||||
assertEquals(StatusCodes.OK, response.toCompletableFuture().get().status());
|
||||
assertEquals(
|
||||
"This is a BOLT request.",
|
||||
response.toCompletableFuture().get().entity().toStrict(3000, materializer).toCompletableFuture().get().getData().utf8String()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.HttpResponse;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.model.headers.Host;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.server.RequestContext;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.model.headers.Location;
|
||||
import akka.http.javadsl.server.directives.DebuggingDirectives;
|
||||
import akka.http.javadsl.server.directives.RouteDirectives;
|
||||
import akka.event.Logging;
|
||||
import akka.event.Logging.LogLevel;
|
||||
import akka.http.javadsl.server.directives.LogEntry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import akka.http.javadsl.server.Rejection;
|
||||
|
||||
import static akka.event.Logging.InfoLevel;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DebuggingDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testLogRequest() {
|
||||
//#logRequest
|
||||
// logs request with "get-user"
|
||||
final Route routeBasicLogRequest = get(() ->
|
||||
logRequest("get-user", () -> complete("logged")));
|
||||
|
||||
// logs request with "get-user" as Info
|
||||
final Route routeBasicLogRequestAsInfo = get(() ->
|
||||
logRequest("get-user", InfoLevel(), () -> complete("logged")));
|
||||
|
||||
// logs just the request method at info level
|
||||
Function<HttpRequest, LogEntry> requestMethodAsInfo = (request) ->
|
||||
LogEntry.create(request.method().name(), InfoLevel());
|
||||
|
||||
final Route routeUsingFunction = get(() ->
|
||||
logRequest(requestMethodAsInfo, () -> complete("logged")));
|
||||
|
||||
// tests:
|
||||
testRoute(routeBasicLogRequest).run(HttpRequest.GET("/"))
|
||||
.assertEntity("logged");
|
||||
//#logRequest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogRequestResult() {
|
||||
//#logRequestResult
|
||||
// using logRequestResult
|
||||
// handle request to optionally generate a log entry
|
||||
BiFunction<HttpRequest, HttpResponse, Optional<LogEntry>> requestMethodAsInfo =
|
||||
(request, response) ->
|
||||
(response.status().isSuccess()) ?
|
||||
Optional.of(
|
||||
LogEntry.create(
|
||||
request.method().name() + ":" + response.status().intValue(),
|
||||
InfoLevel()))
|
||||
: Optional.empty(); // not a successful response
|
||||
|
||||
// handle rejections to optionally generate a log entry
|
||||
BiFunction<HttpRequest, List<Rejection>, Optional<LogEntry>> rejectionsAsInfo =
|
||||
(request, rejections) ->
|
||||
(!rejections.isEmpty()) ?
|
||||
Optional.of(
|
||||
LogEntry.create(
|
||||
rejections
|
||||
.stream()
|
||||
.map(Rejection::toString)
|
||||
.collect(Collectors.joining(", ")),
|
||||
InfoLevel()))
|
||||
: Optional.empty(); // no rejections
|
||||
|
||||
final Route route = get(() -> logRequestResultOptional(
|
||||
requestMethodAsInfo,
|
||||
rejectionsAsInfo,
|
||||
() -> complete("logged")));
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/")).assertEntity("logged");
|
||||
//#logRequestResult
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogResult() {
|
||||
//#logResult
|
||||
// logs result with "get-user"
|
||||
final Route routeBasicLogResult = get(() ->
|
||||
logResult("get-user", () -> complete("logged")));
|
||||
|
||||
// logs result with "get-user" as Info
|
||||
final Route routeBasicLogResultAsInfo = get(() ->
|
||||
logResult("get-user", InfoLevel(), () -> complete("logged")));
|
||||
|
||||
// logs the result and the rejections as LogEntry
|
||||
Function<HttpResponse, LogEntry> showSuccessAsInfo = (response) ->
|
||||
LogEntry.create(String.format("Response code '%d'", response.status().intValue()),
|
||||
InfoLevel());
|
||||
|
||||
Function<List<Rejection>, LogEntry> showRejectionAsInfo = (rejections) ->
|
||||
LogEntry.create(
|
||||
rejections
|
||||
.stream()
|
||||
.map(rejection -> rejection.toString())
|
||||
.collect(Collectors.joining(", ")),
|
||||
InfoLevel());
|
||||
|
||||
final Route routeUsingFunction = get(() ->
|
||||
logResult(showSuccessAsInfo, showRejectionAsInfo, () -> complete("logged")));
|
||||
// tests:
|
||||
testRoute(routeBasicLogResult).run(HttpRequest.GET("/"))
|
||||
.assertEntity("logged");
|
||||
//#logResult
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogRequestResultWithResponseTime() {
|
||||
//#logRequestResultWithResponseTime
|
||||
// using logRequestResultOptional for generating Response Time
|
||||
// handle request to optionally generate a log entry
|
||||
|
||||
BiFunction<HttpRequest, HttpResponse, Optional<LogEntry>> requestMethodAsInfo =
|
||||
(request, response) -> {
|
||||
Long requestTime = System.nanoTime();
|
||||
return printResponseTime(request, response, requestTime);
|
||||
};
|
||||
|
||||
// handle rejections to optionally generate a log entry
|
||||
BiFunction<HttpRequest, List<Rejection>, Optional<LogEntry>> rejectionsAsInfo =
|
||||
(request, rejections) ->
|
||||
(!rejections.isEmpty()) ?
|
||||
Optional.of(
|
||||
LogEntry.create(
|
||||
rejections
|
||||
.stream()
|
||||
.map(Rejection::toString)
|
||||
.collect(Collectors.joining(", ")),
|
||||
InfoLevel()))
|
||||
: Optional.empty(); // no rejections
|
||||
|
||||
final Route route = get(() -> logRequestResultOptional(
|
||||
requestMethodAsInfo,
|
||||
rejectionsAsInfo,
|
||||
() -> complete("logged")));
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/")).assertEntity("logged");
|
||||
//#logRequestResult
|
||||
}
|
||||
|
||||
// A function for the logging of Time
|
||||
public static Optional<LogEntry> printResponseTime(HttpRequest request, HttpResponse response, Long requestTime) {
|
||||
if (response.status().isSuccess()) {
|
||||
Long elapsedTime = (requestTime - System.nanoTime()) / 1000000;
|
||||
return Optional.of(
|
||||
LogEntry.create(
|
||||
"Logged Request:" + request.method().name() + ":" + request.getUri() + ":" + response.status() + ":" + elapsedTime,
|
||||
InfoLevel()));
|
||||
} else {
|
||||
return Optional.empty(); //not a successfull response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-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.server.ExceptionHandler;
|
||||
import akka.http.javadsl.server.PathMatchers;
|
||||
import akka.http.javadsl.server.RejectionHandler;
|
||||
import akka.http.javadsl.server.Rejections;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.server.ValidationRejection;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import static akka.http.javadsl.server.PathMatchers.integerSegment;
|
||||
|
||||
public class ExecutionDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testHandleExceptions() {
|
||||
//#handleExceptions
|
||||
final ExceptionHandler divByZeroHandler = ExceptionHandler.newBuilder()
|
||||
.match(ArithmeticException.class, x ->
|
||||
complete(StatusCodes.BAD_REQUEST, "You've got your arithmetic wrong, fool!"))
|
||||
.build();
|
||||
|
||||
final Route route =
|
||||
path(PathMatchers.segment("divide").slash(integerSegment()).slash(integerSegment()), (a, b) ->
|
||||
handleExceptions(divByZeroHandler, () -> complete("The result is " + (a / b)))
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/divide/10/5"))
|
||||
.assertEntity("The result is 2");
|
||||
testRoute(route).run(HttpRequest.GET("/divide/10/0"))
|
||||
.assertStatusCode(StatusCodes.BAD_REQUEST)
|
||||
.assertEntity("You've got your arithmetic wrong, fool!");
|
||||
//#handleExceptions
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleRejections() {
|
||||
//#handleRejections
|
||||
final RejectionHandler totallyMissingHandler = RejectionHandler.newBuilder()
|
||||
.handleNotFound(complete(StatusCodes.NOT_FOUND, "Oh man, what you are looking for is long gone."))
|
||||
.handle(ValidationRejection.class, r -> complete(StatusCodes.INTERNAL_SERVER_ERROR, r.message()))
|
||||
.build();
|
||||
|
||||
final Route route = pathPrefix("handled", () ->
|
||||
handleRejections(totallyMissingHandler, () ->
|
||||
route(
|
||||
path("existing", () -> complete("This path exists")),
|
||||
path("boom", () -> reject(Rejections.validationRejection("This didn't work.")))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/handled/existing"))
|
||||
.assertEntity("This path exists");
|
||||
// applies default handler
|
||||
testRoute(route).run(HttpRequest.GET("/missing"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND)
|
||||
.assertEntity("The requested resource could not be found.");
|
||||
testRoute(route).run(HttpRequest.GET("/handled/missing"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND)
|
||||
.assertEntity("Oh man, what you are looking for is long gone.");
|
||||
testRoute(route).run(HttpRequest.GET("/handled/boom"))
|
||||
.assertStatusCode(StatusCodes.INTERNAL_SERVER_ERROR)
|
||||
.assertEntity("This didn't work.");
|
||||
//#handleRejections
|
||||
}
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-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.server.PathMatchers;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.server.directives.DirectoryRenderer;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import scala.NotImplementedError;
|
||||
|
||||
import static akka.http.javadsl.server.PathMatchers.segment;
|
||||
|
||||
public class FileAndResourceDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Ignore("Compile only test")
|
||||
@Test
|
||||
public void testGetFromFile() {
|
||||
//#getFromFile
|
||||
final Route route = path(PathMatchers.segment("logs").slash(segment()), name ->
|
||||
getFromFile(name + ".log")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/logs/example"))
|
||||
.assertEntity("example file contents");
|
||||
//#getFromFile
|
||||
}
|
||||
|
||||
@Ignore("Compile only test")
|
||||
@Test
|
||||
public void testGetFromResource() {
|
||||
//#getFromResource
|
||||
final Route route = path(PathMatchers.segment("logs").slash(segment()), name ->
|
||||
getFromResource(name + ".log")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/logs/example"))
|
||||
.assertEntity("example file contents");
|
||||
//#getFromResource
|
||||
}
|
||||
|
||||
@Ignore("Compile only test")
|
||||
@Test
|
||||
public void testListDirectoryContents() {
|
||||
//#listDirectoryContents
|
||||
final Route route = route(
|
||||
path("tmp", () -> listDirectoryContents("/tmp")),
|
||||
path("custom", () -> {
|
||||
// implement your custom renderer here
|
||||
final DirectoryRenderer renderer = renderVanityFooter -> {
|
||||
throw new NotImplementedError();
|
||||
};
|
||||
return listDirectoryContents(renderer, "/tmp");
|
||||
})
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/logs/example"))
|
||||
.assertEntity("example file contents");
|
||||
//#listDirectoryContents
|
||||
}
|
||||
|
||||
@Ignore("Compile only test")
|
||||
@Test
|
||||
public void testGetFromBrowseableDirectory() {
|
||||
//#getFromBrowseableDirectory
|
||||
final Route route = path("tmp", () ->
|
||||
getFromBrowseableDirectory("/tmp")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/tmp"))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
//#getFromBrowseableDirectory
|
||||
}
|
||||
|
||||
@Ignore("Compile only test")
|
||||
@Test
|
||||
public void testGetFromBrowseableDirectories() {
|
||||
//#getFromBrowseableDirectories
|
||||
final Route route = path("tmp", () ->
|
||||
getFromBrowseableDirectories("/main", "/backups")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/tmp"))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
//#getFromBrowseableDirectories
|
||||
}
|
||||
|
||||
@Ignore("Compile only test")
|
||||
@Test
|
||||
public void testGetFromDirectory() {
|
||||
//#getFromDirectory
|
||||
final Route route = pathPrefix("tmp", () ->
|
||||
getFromDirectory("/tmp")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/tmp/example"))
|
||||
.assertEntity("example file contents");
|
||||
//#getFromDirectory
|
||||
}
|
||||
|
||||
@Ignore("Compile only test")
|
||||
@Test
|
||||
public void testGetFromResourceDirectory() {
|
||||
//#getFromResourceDirectory
|
||||
final Route route = pathPrefix("examples", () ->
|
||||
getFromResourceDirectory("/examples")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/examples/example-1"))
|
||||
.assertEntity("example file contents");
|
||||
//#getFromResourceDirectory
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.impl.engine.rendering.BodyPartRenderer;
|
||||
import akka.http.javadsl.model.*;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.unmarshalling.Unmarshaller;
|
||||
import akka.http.javadsl.server.directives.FileInfo;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.stream.javadsl.Framing;
|
||||
import akka.stream.javadsl.Source;
|
||||
import akka.util.ByteString;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class FileUploadDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testUploadedFile() {
|
||||
//#uploadedFile
|
||||
// function (FileInfo, File) => Route to process the file metadata and file itself
|
||||
BiFunction<FileInfo, File, Route> infoFileRoute =
|
||||
(info, file) -> {
|
||||
// do something with the file and file metadata ...
|
||||
file.delete();
|
||||
return complete(StatusCodes.OK);
|
||||
};
|
||||
|
||||
|
||||
final Route route = uploadedFile("csv", infoFileRoute);
|
||||
|
||||
Map<String, String> filenameMapping = new HashMap<>();
|
||||
filenameMapping.put("filename", "data.csv");
|
||||
|
||||
akka.http.javadsl.model.Multipart.FormData multipartForm =
|
||||
Multiparts.createStrictFormDataFromParts(Multiparts.createFormDataBodyPartStrict("csv",
|
||||
HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8,
|
||||
"1,5,7\n11,13,17"), filenameMapping));
|
||||
|
||||
// test:
|
||||
testRoute(route).run(HttpRequest.POST("/")
|
||||
.withEntity(
|
||||
multipartForm.toEntity(HttpCharsets.UTF_8,
|
||||
BodyPartRenderer
|
||||
.randomBoundaryWithDefaults())))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
//#
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileUpload() {
|
||||
//#fileUpload
|
||||
final Route route = extractRequestContext(ctx -> {
|
||||
// function (FileInfo, Source<ByteString,Object>) => Route to process the file contents
|
||||
BiFunction<FileInfo, Source<ByteString, Object>, Route> processUploadedFile =
|
||||
(metadata, byteSource) -> {
|
||||
CompletionStage<Integer> sumF = byteSource.via(Framing.delimiter(
|
||||
ByteString.fromString("\n"), 1024))
|
||||
.mapConcat(bs -> Arrays.asList(bs.utf8String().split(",")))
|
||||
.map(s -> Integer.parseInt(s))
|
||||
.runFold(0, (acc, n) -> acc + n, ctx.getMaterializer());
|
||||
return onSuccess(() -> sumF, sum -> complete("Sum: " + sum));
|
||||
};
|
||||
return fileUpload("csv", processUploadedFile);
|
||||
});
|
||||
|
||||
Map<String, String> filenameMapping = new HashMap<>();
|
||||
filenameMapping.put("filename", "primes.csv");
|
||||
|
||||
akka.http.javadsl.model.Multipart.FormData multipartForm =
|
||||
Multiparts.createStrictFormDataFromParts(
|
||||
Multiparts.createFormDataBodyPartStrict("csv",
|
||||
HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8,
|
||||
"2,3,5\n7,11,13,17,23\n29,31,37\n"), filenameMapping));
|
||||
|
||||
// test:
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(
|
||||
multipartForm.toEntity(HttpCharsets.UTF_8, BodyPartRenderer.randomBoundaryWithDefaults())))
|
||||
.assertStatusCode(StatusCodes.OK).assertEntityAs(Unmarshaller.entityToString(), "Sum: 178");
|
||||
//#
|
||||
}
|
||||
|
||||
@Ignore("compileOnly")
|
||||
@Test
|
||||
public void testFileProcessing() {
|
||||
//#fileProcessing
|
||||
final Route route = extractRequestContext(ctx -> {
|
||||
// function (FileInfo, Source<ByteString,Object>) => Route to process the file contents
|
||||
BiFunction<FileInfo, Source<ByteString, Object>, Route> processUploadedFile =
|
||||
(metadata, byteSource) -> {
|
||||
CompletionStage<Integer> sumF = byteSource.via(Framing.delimiter(
|
||||
ByteString.fromString("\n"), 1024))
|
||||
.mapConcat(bs -> Arrays.asList(bs.utf8String().split(",")))
|
||||
.map(s -> Integer.parseInt(s))
|
||||
.runFold(0, (acc, n) -> acc + n, ctx.getMaterializer());
|
||||
return onSuccess(() -> sumF, sum -> complete("Sum: " + sum));
|
||||
};
|
||||
return fileUpload("csv", processUploadedFile);
|
||||
});
|
||||
|
||||
Map<String, String> filenameMapping = new HashMap<>();
|
||||
filenameMapping.put("filename", "primes.csv");
|
||||
|
||||
String prefix = "primes";
|
||||
String suffix = ".csv";
|
||||
|
||||
File tempFile = null;
|
||||
try {
|
||||
tempFile = File.createTempFile(prefix, suffix);
|
||||
tempFile.deleteOnExit();
|
||||
Files.write(tempFile.toPath(), Arrays.asList("2,3,5", "7,11,13,17,23", "29,31,37"), Charset.forName("UTF-8"));
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
|
||||
akka.http.javadsl.model.Multipart.FormData multipartForm =
|
||||
Multiparts.createFormDataFromPath("csv", ContentTypes.TEXT_PLAIN_UTF8, tempFile.toPath());
|
||||
|
||||
// test:
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(
|
||||
multipartForm.toEntity(HttpCharsets.UTF_8, BodyPartRenderer.randomBoundaryWithDefaults())))
|
||||
.assertStatusCode(StatusCodes.OK).assertEntityAs(Unmarshaller.entityToString(), "Sum: 178");
|
||||
//#
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.FormData;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.unmarshalling.StringUnmarshallers;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.japi.Pair;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FormFieldDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testFormField() {
|
||||
//#formField
|
||||
final Route route = route(
|
||||
formField("color", color ->
|
||||
complete("The color is '" + color + "'")
|
||||
),
|
||||
formField(StringUnmarshallers.INTEGER, "id", id ->
|
||||
complete("The id is '" + id + "'")
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
final FormData formData = FormData.create(Pair.create("color", "blue"));
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(formData.toEntity()))
|
||||
.assertEntity("The color is 'blue'");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertStatusCode(StatusCodes.BAD_REQUEST)
|
||||
.assertEntity("Request is missing required form field 'color'");
|
||||
//#formField
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormFieldMap() {
|
||||
//#formFieldMap
|
||||
final Function<Map<String, String>, String> mapToString = map ->
|
||||
map.entrySet()
|
||||
.stream()
|
||||
.map(e -> e.getKey() + " = '" + e.getValue() +"'")
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
|
||||
final Route route = formFieldMap(fields ->
|
||||
complete("The form fields are " + mapToString.apply(fields))
|
||||
);
|
||||
|
||||
// tests:
|
||||
final FormData formDataDiffKey =
|
||||
FormData.create(
|
||||
Pair.create("color", "blue"),
|
||||
Pair.create("count", "42"));
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(formDataDiffKey.toEntity()))
|
||||
.assertEntity("The form fields are color = 'blue', count = '42'");
|
||||
|
||||
final FormData formDataSameKey =
|
||||
FormData.create(
|
||||
Pair.create("x", "1"),
|
||||
Pair.create("x", "5"));
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(formDataSameKey.toEntity()))
|
||||
.assertEntity( "The form fields are x = '5'");
|
||||
//#formFieldMap
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormFieldMultiMap() {
|
||||
//#formFieldMultiMap
|
||||
final Function<Map<String, List<String>>, String> mapToString = map ->
|
||||
map.entrySet()
|
||||
.stream()
|
||||
.map(e -> e.getKey() + " -> " + e.getValue().size())
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
final Route route = formFieldMultiMap(fields ->
|
||||
complete("There are form fields " + mapToString.apply(fields))
|
||||
);
|
||||
|
||||
// test:
|
||||
final FormData formDataDiffKey =
|
||||
FormData.create(
|
||||
Pair.create("color", "blue"),
|
||||
Pair.create("count", "42"));
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(formDataDiffKey.toEntity()))
|
||||
.assertEntity("There are form fields color -> 1, count -> 1");
|
||||
|
||||
final FormData formDataSameKey =
|
||||
FormData.create(
|
||||
Pair.create("x", "23"),
|
||||
Pair.create("x", "4"),
|
||||
Pair.create("x", "89"));
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(formDataSameKey.toEntity()))
|
||||
.assertEntity("There are form fields x -> 3");
|
||||
//#formFieldMultiMap
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormFieldList() {
|
||||
//#formFieldList
|
||||
final Function<List<Entry<String, String>>, String> listToString = list ->
|
||||
list.stream()
|
||||
.map(e -> e.getKey() + " = '" + e.getValue() +"'")
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
final Route route = formFieldList(fields ->
|
||||
complete("The form fields are " + listToString.apply(fields))
|
||||
);
|
||||
|
||||
// tests:
|
||||
final FormData formDataDiffKey =
|
||||
FormData.create(
|
||||
Pair.create("color", "blue"),
|
||||
Pair.create("count", "42"));
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(formDataDiffKey.toEntity()))
|
||||
.assertEntity("The form fields are color = 'blue', count = '42'");
|
||||
|
||||
final FormData formDataSameKey =
|
||||
FormData.create(
|
||||
Pair.create("x", "23"),
|
||||
Pair.create("x", "4"),
|
||||
Pair.create("x", "89"));
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity(formDataSameKey.toEntity()))
|
||||
.assertEntity("The form fields are x = '23', x = '4', x = '89'");
|
||||
//#formFieldList
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.marshalling.Marshaller;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.scaladsl.model.StatusCodes;
|
||||
import akka.japi.pf.PFBuilder;
|
||||
import akka.pattern.CircuitBreaker;
|
||||
import org.junit.Test;
|
||||
import scala.concurrent.duration.FiniteDuration;
|
||||
|
||||
import static akka.http.javadsl.server.PathMatchers.*;
|
||||
import static scala.compat.java8.JFunction.func;
|
||||
|
||||
public class FutureDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testOnComplete() {
|
||||
//#onComplete
|
||||
// import static scala.compat.java8.JFunction.func;
|
||||
// import static akka.http.javadsl.server.PathMatchers.*;
|
||||
|
||||
final Route route = path(segment("divide").slash(integerSegment()).slash(integerSegment()),
|
||||
(a, b) -> onComplete(
|
||||
() -> CompletableFuture.supplyAsync(() -> a / b),
|
||||
maybeResult -> maybeResult
|
||||
.map(func(result -> complete("The result was " + result)))
|
||||
.recover(new PFBuilder<Throwable, Route>()
|
||||
.matchAny(ex -> complete(StatusCodes.InternalServerError(),
|
||||
"An error occurred: " + ex.getMessage())
|
||||
)
|
||||
.build())
|
||||
.get()
|
||||
)
|
||||
);
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/divide/10/2"))
|
||||
.assertEntity("The result was 5");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/divide/10/0"))
|
||||
.assertStatusCode(StatusCodes.InternalServerError())
|
||||
.assertEntity("An error occurred: / by zero");
|
||||
//#onComplete
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnSuccess() {
|
||||
//#onSuccess
|
||||
final Route route = path("success", () ->
|
||||
onSuccess(() -> CompletableFuture.supplyAsync(() -> "Ok"),
|
||||
extraction -> complete(extraction)
|
||||
)
|
||||
).orElse(path("failure", () ->
|
||||
onSuccess(() -> CompletableFuture.supplyAsync(() -> {
|
||||
throw new RuntimeException();
|
||||
}),
|
||||
extraction -> complete("never reaches here"))
|
||||
));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/success"))
|
||||
.assertEntity("Ok");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/failure"))
|
||||
.assertStatusCode(StatusCodes.InternalServerError())
|
||||
.assertEntity("There was an internal server error.");
|
||||
//#onSuccess
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompleteOrRecoverWith() {
|
||||
//#completeOrRecoverWith
|
||||
final Route route = path("success", () ->
|
||||
completeOrRecoverWith(
|
||||
() -> CompletableFuture.supplyAsync(() -> "Ok"),
|
||||
Marshaller.stringToEntity(),
|
||||
extraction -> failWith(extraction) // not executed
|
||||
)
|
||||
).orElse(path("failure", () ->
|
||||
completeOrRecoverWith(
|
||||
() -> CompletableFuture.supplyAsync(() -> {
|
||||
throw new RuntimeException();
|
||||
}),
|
||||
Marshaller.stringToEntity(),
|
||||
extraction -> failWith(extraction))
|
||||
));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/success"))
|
||||
.assertEntity("Ok");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/failure"))
|
||||
.assertStatusCode(StatusCodes.InternalServerError())
|
||||
.assertEntity("There was an internal server error.");
|
||||
//#completeOrRecoverWith
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnCompleteWithBreaker() throws InterruptedException {
|
||||
//#onCompleteWithBreaker
|
||||
// import static scala.compat.java8.JFunction.func;
|
||||
// import static akka.http.javadsl.server.PathMatchers.*;
|
||||
|
||||
final int maxFailures = 1;
|
||||
final FiniteDuration callTimeout = FiniteDuration.create(5, TimeUnit.SECONDS);
|
||||
final FiniteDuration resetTimeout = FiniteDuration.create(1, TimeUnit.SECONDS);
|
||||
final CircuitBreaker breaker = CircuitBreaker.create(system().scheduler(), maxFailures, callTimeout, resetTimeout);
|
||||
|
||||
final Route route = path(segment("divide").slash(integerSegment()).slash(integerSegment()),
|
||||
(a, b) -> onCompleteWithBreaker(breaker,
|
||||
() -> CompletableFuture.supplyAsync(() -> a / b),
|
||||
maybeResult -> maybeResult
|
||||
.map(func(result -> complete("The result was " + result)))
|
||||
.recover(new PFBuilder<Throwable, Route>()
|
||||
.matchAny(ex -> complete(StatusCodes.InternalServerError(),
|
||||
"An error occurred: " + ex.getMessage())
|
||||
)
|
||||
.build())
|
||||
.get()
|
||||
)
|
||||
);
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/divide/10/2"))
|
||||
.assertEntity("The result was 5");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/divide/10/0"))
|
||||
.assertStatusCode(StatusCodes.InternalServerError())
|
||||
.assertEntity("An error occurred: / by zero");
|
||||
// opened the circuit-breaker
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/divide/10/0"))
|
||||
.assertStatusCode(StatusCodes.ServiceUnavailable())
|
||||
.assertEntity("The server is currently unavailable (because it is overloaded or down for maintenance).");
|
||||
|
||||
Thread.sleep(resetTimeout.toMillis() + 300);
|
||||
// circuit breaker resets after this time
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/divide/8/2"))
|
||||
.assertEntity("The result was 4");
|
||||
|
||||
//#onCompleteWithBreaker
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,261 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import akka.http.javadsl.model.HttpHeader;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.model.headers.Host;
|
||||
import akka.http.javadsl.model.headers.HttpOrigin;
|
||||
import akka.http.javadsl.model.headers.HttpOriginRange;
|
||||
import akka.http.javadsl.model.headers.Origin;
|
||||
import akka.http.javadsl.model.headers.RawHeader;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.japi.JavaPartialFunction;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import scala.PartialFunction;
|
||||
|
||||
public class HeaderDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testHeaderValue() {
|
||||
//#headerValue
|
||||
final Function<HttpHeader, Optional<Host>> extractHostPort = header -> {
|
||||
if (header instanceof Host) {
|
||||
return Optional.of((Host) header);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = headerValue(extractHostPort, host ->
|
||||
complete("The port was " + host.port())
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Host.create("example.com", 5043)))
|
||||
.assertEntity("The port was 5043");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND)
|
||||
.assertEntity("The requested resource could not be found.");
|
||||
//#headerValue
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderValueByName() {
|
||||
//#headerValueByName
|
||||
final Route route = headerValueByName("X-User-Id", userId ->
|
||||
complete("The user is " + userId)
|
||||
);
|
||||
|
||||
// tests:
|
||||
final RawHeader header = RawHeader.create("X-User-Id", "Joe42");
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(header))
|
||||
.assertEntity("The user is Joe42");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertStatusCode(StatusCodes.BAD_REQUEST)
|
||||
.assertEntity("Request is missing required HTTP header 'X-User-Id'");
|
||||
//#headerValueByName
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderValueByType() {
|
||||
//#headerValueByType
|
||||
final Route route = headerValueByType(Origin.class, origin ->
|
||||
complete("The first origin was " + origin.getOrigins().iterator().next())
|
||||
);
|
||||
|
||||
// tests:
|
||||
final Host host = Host.create("localhost", 8080);
|
||||
final Origin originHeader = Origin.create(HttpOrigin.create("http", host));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("abc").addHeader(originHeader))
|
||||
.assertEntity("The first origin was http://localhost:8080");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("abc"))
|
||||
.assertStatusCode(StatusCodes.BAD_REQUEST)
|
||||
.assertEntity("Request is missing required HTTP header 'Origin'");
|
||||
//#headerValueByType
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderValuePF() {
|
||||
//#headerValuePF
|
||||
final PartialFunction<HttpHeader, Integer> extractHostPort =
|
||||
new JavaPartialFunction<HttpHeader, Integer>() {
|
||||
@Override
|
||||
public Integer apply(HttpHeader x, boolean isCheck) throws Exception {
|
||||
if (x instanceof Host) {
|
||||
if (isCheck) {
|
||||
return null;
|
||||
} else {
|
||||
return ((Host) x).port();
|
||||
}
|
||||
} else {
|
||||
throw noMatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = headerValuePF(extractHostPort, port ->
|
||||
complete("The port was " + port)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Host.create("example.com", 5043)))
|
||||
.assertEntity("The port was 5043");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND)
|
||||
.assertEntity("The requested resource could not be found.");
|
||||
//#headerValuePF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalHeaderValue() {
|
||||
//#optionalHeaderValue
|
||||
final Function<HttpHeader, Optional<Integer>> extractHostPort = header -> {
|
||||
if (header instanceof Host) {
|
||||
return Optional.of(((Host) header).port());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = optionalHeaderValue(extractHostPort, port -> {
|
||||
if (port.isPresent()) {
|
||||
return complete("The port was " + port.get());
|
||||
} else {
|
||||
return complete("The port was not provided explicitly");
|
||||
}
|
||||
});
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Host.create("example.com", 5043)))
|
||||
.assertEntity("The port was 5043");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("The port was not provided explicitly");
|
||||
//#optionalHeaderValue
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalHeaderValueByName() {
|
||||
//#optionalHeaderValueByName
|
||||
final Route route = optionalHeaderValueByName("X-User-Id", userId -> {
|
||||
if (userId.isPresent()) {
|
||||
return complete("The user is " + userId.get());
|
||||
} else {
|
||||
return complete("No user was provided");
|
||||
}
|
||||
});
|
||||
|
||||
// tests:
|
||||
final RawHeader header = RawHeader.create("X-User-Id", "Joe42");
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(header))
|
||||
.assertEntity("The user is Joe42");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/")).assertEntity("No user was provided");
|
||||
//#optionalHeaderValueByName
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalHeaderValueByType() {
|
||||
//#optionalHeaderValueByType
|
||||
final Route route = optionalHeaderValueByType(Origin.class, origin -> {
|
||||
if (origin.isPresent()) {
|
||||
return complete("The first origin was " + origin.get().getOrigins().iterator().next());
|
||||
} else {
|
||||
return complete("No Origin header found.");
|
||||
}
|
||||
});
|
||||
|
||||
// tests:
|
||||
|
||||
// extract Some(header) if the type is matching
|
||||
Host host = Host.create("localhost", 8080);
|
||||
Origin originHeader = Origin.create(HttpOrigin.create("http", host));
|
||||
testRoute(route).run(HttpRequest.GET("abc").addHeader(originHeader))
|
||||
.assertEntity("The first origin was http://localhost:8080");
|
||||
|
||||
// extract None if no header of the given type is present
|
||||
testRoute(route).run(HttpRequest.GET("abc")).assertEntity("No Origin header found.");
|
||||
|
||||
//#optionalHeaderValueByType
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalHeaderValuePF() {
|
||||
//#optionalHeaderValuePF
|
||||
final PartialFunction<HttpHeader, Integer> extractHostPort =
|
||||
new JavaPartialFunction<HttpHeader, Integer>() {
|
||||
@Override
|
||||
public Integer apply(HttpHeader x, boolean isCheck) throws Exception {
|
||||
if (x instanceof Host) {
|
||||
if (isCheck) {
|
||||
return null;
|
||||
} else {
|
||||
return ((Host) x).port();
|
||||
}
|
||||
} else {
|
||||
throw noMatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = optionalHeaderValuePF(extractHostPort, port -> {
|
||||
if (port.isPresent()) {
|
||||
return complete("The port was " + port.get());
|
||||
} else {
|
||||
return complete("The port was not provided explicitly");
|
||||
}
|
||||
});
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Host.create("example.com", 5043)))
|
||||
.assertEntity("The port was 5043");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("The port was not provided explicitly");
|
||||
//#optionalHeaderValuePF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckSameOrigin() {
|
||||
//#checkSameOrigin
|
||||
final HttpOrigin validOriginHeader =
|
||||
HttpOrigin.create("http://localhost", Host.create("8080"));
|
||||
|
||||
final HttpOriginRange validOriginRange = HttpOriginRange.create(validOriginHeader);
|
||||
|
||||
final TestRoute route = testRoute(
|
||||
checkSameOrigin(validOriginRange,
|
||||
() -> complete("Result")));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(Origin.create(validOriginHeader)))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("Result");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(StatusCodes.BAD_REQUEST);
|
||||
|
||||
final HttpOrigin invalidOriginHeader =
|
||||
HttpOrigin.create("http://invalid.com", Host.create("8080"));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(Origin.create(invalidOriginHeader)))
|
||||
.assertStatusCode(StatusCodes.FORBIDDEN);
|
||||
//#checkSameOrigin
|
||||
}
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
|
||||
public class HostDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testListOfHost() {
|
||||
//#host1
|
||||
final Route matchListOfHosts = host(
|
||||
Arrays.asList("api.company.com", "rest.company.com"),
|
||||
() -> complete(StatusCodes.OK));
|
||||
|
||||
testRoute(matchListOfHosts).run(HttpRequest.GET("/").addHeader(Host.create("api.company.com")))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
//#host1
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostPredicate() {
|
||||
//#host2
|
||||
final Route shortOnly = host(hostname -> hostname.length() < 10,
|
||||
() -> complete(StatusCodes.OK));
|
||||
|
||||
testRoute(shortOnly).run(HttpRequest.GET("/").addHeader(Host.create("short.com")))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
|
||||
testRoute(shortOnly).run(HttpRequest.GET("/").addHeader(Host.create("verylonghostname.com")))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND);
|
||||
//#host2
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractHost() {
|
||||
//#extractHostname
|
||||
|
||||
final Route route = extractHost(hn ->
|
||||
complete("Hostname: " + hn));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Host.create("company.com", 9090)))
|
||||
.assertEntity("Hostname: company.com");
|
||||
//#extractHostname
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchAndExtractHost() {
|
||||
//#matchAndExtractHost
|
||||
|
||||
final Route hostPrefixRoute = host(Pattern.compile("api|rest"), prefix ->
|
||||
complete("Extracted prefix: " + prefix));
|
||||
|
||||
final Route hostPartRoute = host(Pattern.compile("public.(my|your)company.com"), captured ->
|
||||
complete("You came through " + captured
|
||||
+ " company"));
|
||||
|
||||
final Route route = route(hostPrefixRoute, hostPartRoute);
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Host.create("api.company.com")))
|
||||
.assertStatusCode(StatusCodes.OK).assertEntity("Extracted prefix: api");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/").addHeader(Host.create("public.mycompany.com")))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("You came through my company");
|
||||
//#matchAndExtractHost
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testFailingMatchAndExtractHost() {
|
||||
//#failing-matchAndExtractHost
|
||||
// this will throw IllegalArgumentException
|
||||
final Route hostRegex = host(Pattern.compile("server-([0-9]).company.(com|net|org)"), s ->
|
||||
// will not reach here
|
||||
complete(s)
|
||||
);
|
||||
//#failing-matchAndExtractHost
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
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.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
|
||||
public class MethodDirectivesExamplesTest extends JUnitRouteTest {
|
||||
@Test
|
||||
public void testDelete() {
|
||||
//#delete
|
||||
final Route route = delete(() -> complete("This is a DELETE request."));
|
||||
|
||||
testRoute(route).run(HttpRequest.DELETE("/")).assertEntity(
|
||||
"This is a DELETE request.");
|
||||
//#delete
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet() {
|
||||
//#get
|
||||
final Route route = get(() -> complete("This is a GET request."));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/")).assertEntity(
|
||||
"This is a GET request.");
|
||||
//#get
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHead() {
|
||||
//#head
|
||||
final Route route = head(() -> complete("This is a HEAD request."));
|
||||
|
||||
testRoute(route).run(HttpRequest.HEAD("/")).assertEntity(
|
||||
"This is a HEAD request.");
|
||||
//#head
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptions() {
|
||||
//#options
|
||||
final Route route = options(() -> complete("This is a OPTIONS request."));
|
||||
|
||||
testRoute(route).run(HttpRequest.OPTIONS("/")).assertEntity(
|
||||
"This is a OPTIONS request.");
|
||||
//#options
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatch() {
|
||||
//#patch
|
||||
final Route route = patch(() -> complete("This is a PATCH request."));
|
||||
|
||||
testRoute(route).run(HttpRequest.PATCH("/").withEntity("patch content"))
|
||||
.assertEntity("This is a PATCH request.");
|
||||
//#patch
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost() {
|
||||
//#post
|
||||
final Route route = post(() -> complete("This is a POST request."));
|
||||
|
||||
testRoute(route).run(HttpRequest.POST("/").withEntity("post content"))
|
||||
.assertEntity("This is a POST request.");
|
||||
//#post
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPut() {
|
||||
//#put
|
||||
final Route route = put(() -> complete("This is a PUT request."));
|
||||
|
||||
testRoute(route).run(HttpRequest.PUT("/").withEntity("put content"))
|
||||
.assertEntity("This is a PUT request.");
|
||||
//#put
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodExample() {
|
||||
//#method-example
|
||||
final Route route = method(HttpMethods.PUT,
|
||||
() -> complete("This is a PUT request."));
|
||||
|
||||
testRoute(route).run(HttpRequest.PUT("/").withEntity("put content"))
|
||||
.assertEntity("This is a PUT request.");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/")).assertStatusCode(
|
||||
StatusCodes.METHOD_NOT_ALLOWED);
|
||||
//#method-example
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractMethodExample() {
|
||||
//#extractMethod
|
||||
|
||||
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.");
|
||||
|
||||
testRoute(route).run(HttpRequest.PUT("/").withEntity("put content"))
|
||||
.assertEntity("This PUT request, clearly is not a GET!");
|
||||
|
||||
testRoute(route).run(HttpRequest.HEAD("/")).assertEntity(
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-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.server.Route;
|
||||
import akka.http.javadsl.unmarshalling.Unmarshaller;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class MiscDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testWithSizeLimit() {
|
||||
//#withSizeLimitExample
|
||||
final Route route = withSizeLimit(500, () ->
|
||||
entity(Unmarshaller.entityToString(), (entity) ->
|
||||
complete("ok")
|
||||
)
|
||||
);
|
||||
|
||||
Function<Integer, HttpRequest> withEntityOfSize = (sizeLimit) -> {
|
||||
char[] charArray = new char[sizeLimit];
|
||||
Arrays.fill(charArray, '0');
|
||||
return HttpRequest.POST("/").withEntity(new String(charArray));
|
||||
};
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(withEntityOfSize.apply(500))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
|
||||
testRoute(route).run(withEntityOfSize.apply(501))
|
||||
.assertStatusCode(StatusCodes.BAD_REQUEST);
|
||||
//#withSizeLimitExample
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithoutSizeLimit() {
|
||||
//#withoutSizeLimitExample
|
||||
final Route route = withoutSizeLimit(() ->
|
||||
entity(Unmarshaller.entityToString(), (entity) ->
|
||||
complete("ok")
|
||||
)
|
||||
);
|
||||
|
||||
Function<Integer, HttpRequest> withEntityOfSize = (sizeLimit) -> {
|
||||
char[] charArray = new char[sizeLimit];
|
||||
Arrays.fill(charArray, '0');
|
||||
return HttpRequest.POST("/").withEntity(new String(charArray));
|
||||
};
|
||||
|
||||
// tests:
|
||||
// will work even if you have configured akka.http.parsing.max-content-length = 500
|
||||
testRoute(route).run(withEntityOfSize.apply(501))
|
||||
.assertStatusCode(StatusCodes.OK);
|
||||
//#withoutSizeLimitExample
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-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.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ParameterDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testParameter() {
|
||||
//#parameter
|
||||
final Route route = parameter("color", color ->
|
||||
complete("The color is '" + color + "'")
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/?color=blue"))
|
||||
.assertEntity("The color is 'blue'");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND)
|
||||
.assertEntity("Request is missing required query parameter 'color'");
|
||||
//#parameter
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameters() {
|
||||
//#parameters
|
||||
final Route route = parameter("color", color ->
|
||||
parameter("backgroundColor", backgroundColor ->
|
||||
complete("The color is '" + color
|
||||
+ "' and the background is '" + backgroundColor + "'")
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/?color=blue&backgroundColor=red"))
|
||||
.assertEntity("The color is 'blue' and the background is 'red'");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/?color=blue"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND)
|
||||
.assertEntity("Request is missing required query parameter 'backgroundColor'");
|
||||
//#parameters
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterMap() {
|
||||
//#parameterMap
|
||||
final Function<Entry, String> paramString =
|
||||
entry -> entry.getKey() + " = '" + entry.getValue() + "'";
|
||||
|
||||
final Route route = parameterMap(params -> {
|
||||
final String pString = params.entrySet()
|
||||
.stream()
|
||||
.map(paramString::apply)
|
||||
.collect(Collectors.joining(", "));
|
||||
return complete("The parameters are " + pString);
|
||||
});
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/?color=blue&count=42"))
|
||||
.assertEntity("The parameters are color = 'blue', count = '42'");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/?x=1&x=2"))
|
||||
.assertEntity("The parameters are x = '2'");
|
||||
//#parameterMap
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterMultiMap() {
|
||||
//#parameterMultiMap
|
||||
final Route route = parameterMultiMap(params -> {
|
||||
final String pString = params.entrySet()
|
||||
.stream()
|
||||
.map(e -> e.getKey() + " -> " + e.getValue().size())
|
||||
.collect(Collectors.joining(", "));
|
||||
return complete("There are parameters " + pString);
|
||||
});
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/?color=blue&count=42"))
|
||||
.assertEntity("There are parameters color -> 1, count -> 1");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/?x=23&x=42"))
|
||||
.assertEntity("There are parameters x -> 2");
|
||||
//#parameterMultiMap
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterSeq() {
|
||||
//#parameterSeq
|
||||
final Function<Entry, String> paramString =
|
||||
entry -> entry.getKey() + " = '" + entry.getValue() + "'";
|
||||
|
||||
final Route route = parameterList(params -> {
|
||||
final String pString = params.stream()
|
||||
.map(paramString::apply)
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
return complete("The parameters are " + pString);
|
||||
});
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/?color=blue&count=42"))
|
||||
.assertEntity("The parameters are color = 'blue', count = '42'");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/?x=1&x=2"))
|
||||
.assertEntity("The parameters are x = '1', x = '2'");
|
||||
//#parameterSeq
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,322 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import static akka.http.javadsl.server.PathMatchers.segment;
|
||||
import static akka.http.javadsl.server.PathMatchers.segments;
|
||||
import static akka.http.javadsl.server.PathMatchers.integerSegment;
|
||||
import static akka.http.javadsl.server.PathMatchers.neutral;
|
||||
import static akka.http.javadsl.server.PathMatchers.slash;
|
||||
import java.util.function.Supplier;
|
||||
import akka.http.javadsl.server.directives.RouteAdapter;
|
||||
import static java.util.regex.Pattern.compile;
|
||||
|
||||
public class PathDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
//# path-prefix-test, path-suffix, raw-path-prefix, raw-path-prefix-test
|
||||
Supplier<RouteAdapter> completeWithUnmatchedPath = ()->
|
||||
extractUnmatchedPath((path) -> complete(path.toString()));
|
||||
//#
|
||||
|
||||
@Test
|
||||
public void testPathExamples() {
|
||||
//# path-dsl
|
||||
// matches /foo/
|
||||
path(segment("foo").slash(), () -> complete(StatusCodes.OK));
|
||||
|
||||
// matches e.g. /foo/123 and extracts "123" as a String
|
||||
path(segment("foo").slash(segment(compile("\\d+"))), (value) ->
|
||||
complete(StatusCodes.OK));
|
||||
|
||||
// matches e.g. /foo/bar123 and extracts "123" as a String
|
||||
path(segment("foo").slash(segment(compile("bar(\\d+)"))), (value) ->
|
||||
complete(StatusCodes.OK));
|
||||
|
||||
// similar to `path(Segments)`
|
||||
path(neutral().repeat(0, 10), () -> complete(StatusCodes.OK));
|
||||
|
||||
// identical to path("foo" ~ (PathEnd | Slash))
|
||||
path(segment("foo").orElse(slash()), () -> complete(StatusCodes.OK));
|
||||
//# path-dsl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicExamples() {
|
||||
path("test", () -> complete(StatusCodes.OK));
|
||||
|
||||
// matches "/test", as well
|
||||
path(segment("test"), () -> complete(StatusCodes.OK));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathExample() {
|
||||
//# pathPrefix
|
||||
final Route route =
|
||||
route(
|
||||
path("foo", () -> complete("/foo")),
|
||||
path(segment("foo").slash("bar"), () -> complete("/foo/bar")),
|
||||
pathPrefix("ball", () ->
|
||||
route(
|
||||
pathEnd(() -> complete("/ball")),
|
||||
path(integerSegment(), (i) ->
|
||||
complete((i % 2 == 0) ? "even ball" : "odd ball"))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/")).assertStatusCode(StatusCodes.NOT_FOUND);
|
||||
testRoute(route).run(HttpRequest.GET("/foo")).assertEntity("/foo");
|
||||
testRoute(route).run(HttpRequest.GET("/foo/bar")).assertEntity("/foo/bar");
|
||||
testRoute(route).run(HttpRequest.GET("/ball/1337")).assertEntity("odd ball");
|
||||
//# pathPrefix
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathEnd() {
|
||||
//# path-end
|
||||
final Route route =
|
||||
route(
|
||||
pathPrefix("foo", () ->
|
||||
route(
|
||||
pathEnd(() -> complete("/foo")),
|
||||
path("bar", () -> complete("/foo/bar"))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foo")).assertEntity("/foo");
|
||||
testRoute(route).run(HttpRequest.GET("/foo/")).assertStatusCode(StatusCodes.NOT_FOUND);
|
||||
testRoute(route).run(HttpRequest.GET("/foo/bar")).assertEntity("/foo/bar");
|
||||
//# path-end
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathEndOrSingleSlash() {
|
||||
//# path-end-or-single-slash
|
||||
final Route route =
|
||||
route(
|
||||
pathPrefix("foo", () ->
|
||||
route(
|
||||
pathEndOrSingleSlash(() -> complete("/foo")),
|
||||
path("bar", () -> complete("/foo/bar"))
|
||||
)
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foo")).assertEntity("/foo");
|
||||
testRoute(route).run(HttpRequest.GET("/foo/")).assertEntity("/foo");
|
||||
testRoute(route).run(HttpRequest.GET("/foo/bar")).assertEntity("/foo/bar");
|
||||
//# path-end-or-single-slash
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathPrefix() {
|
||||
//# path-prefix
|
||||
final Route route =
|
||||
route(
|
||||
pathPrefix("ball", () ->
|
||||
route(
|
||||
pathEnd(() -> complete("/ball")),
|
||||
path(integerSegment(), (i) ->
|
||||
complete((i % 2 == 0) ? "even ball" : "odd ball"))
|
||||
)
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/")).assertStatusCode(StatusCodes.NOT_FOUND);
|
||||
testRoute(route).run(HttpRequest.GET("/ball")).assertEntity("/ball");
|
||||
testRoute(route).run(HttpRequest.GET("/ball/1337")).assertEntity("odd ball");
|
||||
//# path-prefix
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathPrefixTest() {
|
||||
//# path-prefix-test
|
||||
final Route route =
|
||||
route(
|
||||
pathPrefixTest(segment("foo").orElse("bar"), () ->
|
||||
route(
|
||||
pathPrefix("foo", () -> completeWithUnmatchedPath.get()),
|
||||
pathPrefix("bar", () -> completeWithUnmatchedPath.get())
|
||||
)
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foo/doo")).assertEntity("/doo");
|
||||
testRoute(route).run(HttpRequest.GET("/bar/yes")).assertEntity("/yes");
|
||||
//# path-prefix-test
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathSingleSlash() {
|
||||
//# path-single-slash
|
||||
final Route route =
|
||||
route(
|
||||
pathSingleSlash(() -> complete("root")),
|
||||
pathPrefix("ball", () ->
|
||||
route(
|
||||
pathSingleSlash(() -> complete("/ball/")),
|
||||
path(integerSegment(), (i) -> complete((i % 2 == 0) ? "even ball" : "odd ball"))
|
||||
)
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/")).assertEntity("root");
|
||||
testRoute(route).run(HttpRequest.GET("/ball")).assertStatusCode(StatusCodes.NOT_FOUND);
|
||||
testRoute(route).run(HttpRequest.GET("/ball/")).assertEntity("/ball/");
|
||||
testRoute(route).run(HttpRequest.GET("/ball/1337")).assertEntity("odd ball");
|
||||
//# path-single-slash
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathSuffix() {
|
||||
//# path-suffix
|
||||
final Route route =
|
||||
route(
|
||||
pathPrefix("start", () ->
|
||||
route(
|
||||
pathSuffix("end", () -> completeWithUnmatchedPath.get()),
|
||||
pathSuffix(segment("foo").slash("bar").concat("baz"), () ->
|
||||
completeWithUnmatchedPath.get())
|
||||
)
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/start/middle/end")).assertEntity("/middle/");
|
||||
testRoute(route).run(HttpRequest.GET("/start/something/barbaz/foo")).assertEntity("/something/");
|
||||
//# path-suffix
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathSuffixTest() {
|
||||
//# path-suffix-test
|
||||
final Route route =
|
||||
route(
|
||||
pathSuffixTest(slash(), () -> complete("slashed")),
|
||||
complete("unslashed")
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foo/")).assertEntity("slashed");
|
||||
testRoute(route).run(HttpRequest.GET("/foo")).assertEntity("unslashed");
|
||||
//# path-suffix-test
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawPathPrefix() {
|
||||
//# raw-path-prefix
|
||||
final Route route =
|
||||
route(
|
||||
pathPrefix("foo", () ->
|
||||
route(
|
||||
rawPathPrefix("bar", () -> completeWithUnmatchedPath.get()),
|
||||
rawPathPrefix("doo", () -> completeWithUnmatchedPath.get())
|
||||
)
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foobar/baz")).assertEntity("/baz");
|
||||
testRoute(route).run(HttpRequest.GET("/foodoo/baz")).assertEntity("/baz");
|
||||
//# raw-path-prefix
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawPathPrefixTest() {
|
||||
//# raw-path-prefix-test
|
||||
final Route route =
|
||||
route(
|
||||
pathPrefix("foo", () ->
|
||||
rawPathPrefixTest("bar", () -> completeWithUnmatchedPath.get())
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foobar")).assertEntity("bar");
|
||||
testRoute(route).run(HttpRequest.GET("/foobaz")).assertStatusCode(StatusCodes.NOT_FOUND);
|
||||
//# raw-path-prefix-test
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectToNoTrailingSlashIfMissing() {
|
||||
//# redirect-notrailing-slash-missing
|
||||
final Route route =
|
||||
redirectToTrailingSlashIfMissing(
|
||||
StatusCodes.MOVED_PERMANENTLY, () ->
|
||||
route(
|
||||
path(segment("foo").slash(), () -> complete("OK")),
|
||||
path(segment("bad-1"), () ->
|
||||
// MISTAKE!
|
||||
// Missing `/` in path, causes this path to never match,
|
||||
// because it is inside a `redirectToTrailingSlashIfMissing`
|
||||
complete(StatusCodes.NOT_IMPLEMENTED)
|
||||
),
|
||||
path(segment("bad-2").slash(), () ->
|
||||
// MISTAKE!
|
||||
// / should be explicit as path element separator and not *in* the path element
|
||||
// So it should be: "bad-1" /
|
||||
complete(StatusCodes.NOT_IMPLEMENTED)
|
||||
)
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foo"))
|
||||
.assertStatusCode(StatusCodes.MOVED_PERMANENTLY)
|
||||
.assertEntity("This and all future requests should be directed to " +
|
||||
"<a href=\"http://example.com/foo/\">this URI</a>.");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/foo/"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("OK");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/bad-1/"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND);
|
||||
//# redirect-notrailing-slash-missing
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectToNoTrailingSlashIfPresent() {
|
||||
//# redirect-notrailing-slash-present
|
||||
final Route route =
|
||||
redirectToNoTrailingSlashIfPresent(
|
||||
StatusCodes.MOVED_PERMANENTLY, () ->
|
||||
route(
|
||||
path("foo", () -> complete("OK")),
|
||||
path(segment("bad").slash(), () ->
|
||||
// MISTAKE!
|
||||
// Since inside a `redirectToNoTrailingSlashIfPresent` directive
|
||||
// the matched path here will never contain a trailing slash,
|
||||
// thus this path will never match.
|
||||
//
|
||||
// It should be `path("bad")` instead.
|
||||
complete(StatusCodes.NOT_IMPLEMENTED)
|
||||
)
|
||||
)
|
||||
);
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foo/"))
|
||||
.assertStatusCode(StatusCodes.MOVED_PERMANENTLY)
|
||||
.assertEntity("This and all future requests should be directed to " +
|
||||
"<a href=\"http://example.com/foo\">this URI</a>.");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/foo"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("OK");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/bad"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND);
|
||||
//# redirect-notrailing-slash-present
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.Multipart;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.model.headers.ByteRange;
|
||||
import akka.http.javadsl.model.headers.ContentRange;
|
||||
import akka.http.javadsl.model.headers.Range;
|
||||
import akka.http.javadsl.model.headers.RangeUnits;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.unmarshalling.Unmarshaller;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRouteResult;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.util.ByteString;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RangeDirectivesExamplesTest extends JUnitRouteTest {
|
||||
@Override
|
||||
public Config additionalConfig() {
|
||||
return ConfigFactory.parseString("akka.http.routing.range-coalescing-threshold=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithRangeSupport() {
|
||||
//#withRangeSupport
|
||||
final Route route = withRangeSupport(() -> complete("ABCDEFGH"));
|
||||
|
||||
// test:
|
||||
final String bytes348Range = ContentRange.create(RangeUnits.BYTES,
|
||||
akka.http.javadsl.model.ContentRange.create(3, 4, 8)).value();
|
||||
final akka.http.javadsl.model.ContentRange bytes028Range =
|
||||
akka.http.javadsl.model.ContentRange.create(0, 2, 8);
|
||||
final akka.http.javadsl.model.ContentRange bytes678Range =
|
||||
akka.http.javadsl.model.ContentRange.create(6, 7, 8);
|
||||
final ActorMaterializer materializer = systemResource().materializer();
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/")
|
||||
.addHeader(Range.create(RangeUnits.BYTES, ByteRange.createSlice(3, 4))))
|
||||
.assertHeaderKindExists("Content-Range")
|
||||
.assertHeaderExists("Content-Range", bytes348Range)
|
||||
.assertStatusCode(StatusCodes.PARTIAL_CONTENT)
|
||||
.assertEntity("DE");
|
||||
|
||||
// we set "akka.http.routing.range-coalescing-threshold = 2"
|
||||
// above to make sure we get two BodyParts
|
||||
final TestRouteResult response = testRoute(route).run(HttpRequest.GET("/")
|
||||
.addHeader(Range.create(RangeUnits.BYTES,
|
||||
ByteRange.createSlice(0, 1), ByteRange.createSlice(1, 2), ByteRange.createSlice(6, 7))));
|
||||
response.assertHeaderKindNotExists("Content-Range");
|
||||
|
||||
final CompletionStage<List<Multipart.ByteRanges.BodyPart>> completionStage =
|
||||
response.entity(Unmarshaller.entityToMultipartByteRanges()).getParts()
|
||||
.runFold(new ArrayList<>(), (acc, n) -> {
|
||||
acc.add(n);
|
||||
return acc;
|
||||
}, materializer);
|
||||
try {
|
||||
final List<Multipart.ByteRanges.BodyPart> bodyParts =
|
||||
completionStage.toCompletableFuture().get(3, TimeUnit.SECONDS);
|
||||
assertEquals(2, bodyParts.toArray().length);
|
||||
|
||||
final Multipart.ByteRanges.BodyPart part1 = bodyParts.get(0);
|
||||
assertEquals(bytes028Range, part1.getContentRange());
|
||||
assertEquals(ByteString.fromString("ABC"),
|
||||
part1.toStrict(1000, materializer).toCompletableFuture().get().getEntity().getData());
|
||||
|
||||
final Multipart.ByteRanges.BodyPart part2 = bodyParts.get(1);
|
||||
assertEquals(bytes678Range, part2.getContentRange());
|
||||
assertEquals(ByteString.fromString("GH"),
|
||||
part2.toStrict(1000, materializer).toCompletableFuture().get().getEntity().getData());
|
||||
|
||||
} catch (Exception e) {
|
||||
// please handle this in production code
|
||||
}
|
||||
//#
|
||||
}
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import java.util.List;
|
||||
import akka.http.javadsl.model.HttpHeader;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.headers.HttpOrigin;
|
||||
import akka.http.javadsl.model.headers.Origin;
|
||||
import akka.http.javadsl.model.headers.RawHeader;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.Test;
|
||||
|
||||
public class RespondWithDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testRespondWithHeader() {
|
||||
//#respondWithHeader
|
||||
final Route route = path("foo", () ->
|
||||
respondWithHeader(RawHeader.create("Funky-Muppet", "gonzo"), () ->
|
||||
complete("beep")));
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/foo"))
|
||||
.assertHeaderExists("Funky-Muppet", "gonzo")
|
||||
.assertEntity("beep");
|
||||
//#respondWithHeader
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRespondWithDefaultHeader() {
|
||||
//#respondWithDefaultHeader
|
||||
//custom headers
|
||||
final RawHeader blippy = RawHeader.create("X-Fish-Name", "Blippy");
|
||||
final RawHeader elTonno = RawHeader.create("X-Fish-Name", "El Tonno");
|
||||
|
||||
// format: OFF
|
||||
// by default always include the Blippy header,
|
||||
// unless a more specific X-Fish-Name is given by the inner route
|
||||
final Route route =
|
||||
respondWithDefaultHeader(blippy, () -> // blippy
|
||||
respondWithHeader(elTonno, () -> // / el tonno
|
||||
path("el-tonno", () -> // | /
|
||||
complete("¡Ay blippy!") // | |- el tonno
|
||||
).orElse( // | |
|
||||
path("los-tonnos", () -> // | |
|
||||
complete("¡Ay ay blippy!") // | |- el tonno
|
||||
) // | |
|
||||
) // | |
|
||||
).orElse( // | x
|
||||
complete("Blip!") // |- blippy
|
||||
) // x
|
||||
);
|
||||
//format: ON
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertHeaderExists("X-Fish-Name", "Blippy")
|
||||
.assertEntity("Blip!");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/el-tonno"))
|
||||
.assertHeaderExists("X-Fish-Name", "El Tonno")
|
||||
.assertEntity("¡Ay blippy!");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/los-tonnos"))
|
||||
.assertHeaderExists("X-Fish-Name", "El Tonno")
|
||||
.assertEntity("¡Ay ay blippy!");
|
||||
//#respondWithDefaultHeader
|
||||
}
|
||||
|
||||
@Test
|
||||
public void respondWithHeaders() {
|
||||
//#respondWithHeaders
|
||||
final HttpHeader gonzo = RawHeader.create("Funky-Muppet", "gonzo");
|
||||
final HttpHeader akka = Origin.create(HttpOrigin.parse("http://akka.io"));
|
||||
|
||||
final Route route = path("foo", () ->
|
||||
respondWithHeaders(Lists.newArrayList(gonzo, akka), () ->
|
||||
complete("beep")
|
||||
)
|
||||
);
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/foo"))
|
||||
.assertHeaderExists("Funky-Muppet", "gonzo")
|
||||
.assertHeaderExists("Origin", "http://akka.io")
|
||||
.assertEntity("beep");
|
||||
|
||||
//#respondWithHeaders
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRespondWithDefaultHeaders() {
|
||||
//#respondWithDefaultHeaders
|
||||
//custom headers
|
||||
final RawHeader blippy = RawHeader.create("X-Fish-Name", "Blippy");
|
||||
final HttpHeader akka = Origin.create(HttpOrigin.parse("http://akka.io"));
|
||||
final List<HttpHeader> defaultHeaders = Lists.newArrayList(blippy, akka);
|
||||
final RawHeader elTonno = RawHeader.create("X-Fish-Name", "El Tonno");
|
||||
|
||||
// format: OFF
|
||||
// by default always include the Blippy and Akka headers,
|
||||
// unless a more specific X-Fish-Name is given by the inner route
|
||||
final Route route =
|
||||
respondWithDefaultHeaders(defaultHeaders, () -> // blippy and akka
|
||||
respondWithHeader(elTonno, () -> // / el tonno
|
||||
path("el-tonno", () -> // | /
|
||||
complete("¡Ay blippy!") // | |- el tonno
|
||||
).orElse( // | |
|
||||
path("los-tonnos", () -> // | |
|
||||
complete("¡Ay ay blippy!") // | |- el tonno
|
||||
) // | |
|
||||
) // | |
|
||||
).orElse( // | x
|
||||
complete("Blip!") // |- blippy and akka
|
||||
) // x
|
||||
);
|
||||
//format: ON
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertHeaderExists("X-Fish-Name", "Blippy")
|
||||
.assertHeaderExists("Origin", "http://akka.io")
|
||||
.assertEntity("Blip!");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/el-tonno"))
|
||||
.assertHeaderExists("X-Fish-Name", "El Tonno")
|
||||
.assertEntity("¡Ay blippy!");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/los-tonnos"))
|
||||
.assertHeaderExists("X-Fish-Name", "El Tonno")
|
||||
.assertEntity("¡Ay ay blippy!");
|
||||
//#respondWithDefaultHeaders
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpEntities;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.model.headers.ContentType;
|
||||
import akka.http.javadsl.model.ContentTypes;
|
||||
import akka.http.javadsl.model.HttpResponse;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.server.Rejections;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class RouteDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testComplete() {
|
||||
//#complete
|
||||
final Route route = route(
|
||||
path("a", () -> complete(HttpResponse.create().withEntity("foo"))),
|
||||
path("b", () -> complete(StatusCodes.OK)),
|
||||
path("c", () -> complete(StatusCodes.CREATED, "bar")),
|
||||
path("d", () -> complete(StatusCodes.get(201), "bar")),
|
||||
path("e", () ->
|
||||
complete(StatusCodes.CREATED,
|
||||
Collections.singletonList(ContentType.create(ContentTypes.TEXT_PLAIN_UTF8)),
|
||||
HttpEntities.create("bar"))),
|
||||
path("f", () ->
|
||||
complete(StatusCodes.get(201),
|
||||
Collections.singletonList(ContentType.create(ContentTypes.TEXT_PLAIN_UTF8)),
|
||||
HttpEntities.create("bar"))),
|
||||
path("g", () -> complete("baz"))
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/a"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("foo");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/b"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("OK");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/c"))
|
||||
.assertStatusCode(StatusCodes.CREATED)
|
||||
.assertEntity("bar");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/d"))
|
||||
.assertStatusCode(StatusCodes.CREATED)
|
||||
.assertEntity("bar");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/e"))
|
||||
.assertStatusCode(StatusCodes.CREATED)
|
||||
.assertHeaderExists(ContentType.create(ContentTypes.TEXT_PLAIN_UTF8))
|
||||
.assertEntity("bar");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/f"))
|
||||
.assertStatusCode(StatusCodes.CREATED)
|
||||
.assertHeaderExists(ContentType.create(ContentTypes.TEXT_PLAIN_UTF8))
|
||||
.assertEntity("bar");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/g"))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("baz");
|
||||
//#complete
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReject() {
|
||||
//#reject
|
||||
final Route route = route(
|
||||
path("a", this::reject), // don't handle here, continue on
|
||||
path("a", () -> complete("foo")),
|
||||
path("b", () -> reject(Rejections.validationRejection("Restricted!")))
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/a"))
|
||||
.assertEntity("foo");
|
||||
|
||||
runRouteUnSealed(route, HttpRequest.GET("/b"))
|
||||
.assertRejections(Rejections.validationRejection("Restricted!"));
|
||||
//#reject
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirect() {
|
||||
//#redirect
|
||||
final Route route = pathPrefix("foo", () ->
|
||||
route(
|
||||
pathSingleSlash(() -> complete("yes")),
|
||||
pathEnd(() -> redirect(Uri.create("/foo/"), StatusCodes.PERMANENT_REDIRECT))
|
||||
)
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foo/"))
|
||||
.assertEntity("yes");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/foo"))
|
||||
.assertStatusCode(StatusCodes.PERMANENT_REDIRECT)
|
||||
.assertEntity("The request, and all future requests should be repeated using <a href=\"/foo/\">this URI</a>.");
|
||||
//#redirect
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailWith() {
|
||||
//#failWith
|
||||
final Route route = path("foo", () ->
|
||||
failWith(new RuntimeException("Oops."))
|
||||
);
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/foo"))
|
||||
.assertStatusCode(StatusCodes.INTERNAL_SERVER_ERROR)
|
||||
.assertEntity("There was an internal server error.");
|
||||
//#failWith
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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.Route;
|
||||
import akka.http.javadsl.server.RequestContext;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import java.util.function.Function;
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.model.headers.Location;
|
||||
|
||||
public class SchemeDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testScheme() {
|
||||
//#extractScheme
|
||||
final Route route = extractScheme((scheme) ->
|
||||
complete(String.format("The scheme is '%s'", scheme)));
|
||||
testRoute(route).run(HttpRequest.GET("https://www.example.com/"))
|
||||
.assertEntity("The scheme is 'https'");
|
||||
//#extractScheme
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirection() {
|
||||
//#scheme
|
||||
final Route route = route(
|
||||
scheme("http", ()->
|
||||
extract((ctx) -> ctx.getRequest().getUri(), (uri)->
|
||||
redirect(uri.scheme("https"), StatusCodes.MOVED_PERMANENTLY)
|
||||
)
|
||||
),
|
||||
scheme("https", ()->
|
||||
complete("Safe and secure!")
|
||||
)
|
||||
);
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("http://www.example.com/hello"))
|
||||
.assertStatusCode(StatusCodes.MOVED_PERMANENTLY)
|
||||
.assertHeaderExists(Location.create("https://www.example.com/hello"))
|
||||
;
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("https://www.example.com/hello"))
|
||||
.assertEntity("Safe and secure!");
|
||||
//#scheme
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,364 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-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.BasicHttpCredentials;
|
||||
import akka.http.javadsl.model.headers.HttpChallenge;
|
||||
import akka.http.javadsl.model.headers.HttpCredentials;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.japi.JavaPartialFunction;
|
||||
import org.junit.Test;
|
||||
import scala.PartialFunction;
|
||||
import scala.util.Either;
|
||||
import scala.util.Left;
|
||||
import scala.util.Right;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.Function;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SecurityDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testAuthenticateBasic() {
|
||||
//#authenticateBasic
|
||||
final Function<Optional<ProvidedCredentials>, Optional<String>> myUserPassAuthenticator =
|
||||
credentials ->
|
||||
credentials.filter(c -> c.verify("p4ssw0rd")).map(ProvidedCredentials::identifier);
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateBasic("secure site", myUserPassAuthenticator, userName ->
|
||||
complete("The user is '" + userName + "'")
|
||||
)
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/secured"))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The resource requires authentication, which was not supplied with the request")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertEntity("The user is 'John'");
|
||||
|
||||
final HttpCredentials invalidCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(invalidCredentials))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The supplied authentication is invalid")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
//#authenticateBasic
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAuthenticateBasicPF() {
|
||||
//#authenticateBasicPF
|
||||
final PartialFunction<Optional<ProvidedCredentials>, String> myUserPassAuthenticator =
|
||||
new JavaPartialFunction<Optional<ProvidedCredentials>, String>() {
|
||||
@Override
|
||||
public String apply(Optional<ProvidedCredentials> opt, boolean isCheck) throws Exception {
|
||||
if (opt.filter(c -> (c != null) && c.verify("p4ssw0rd")).isPresent()) {
|
||||
if (isCheck) return null;
|
||||
else return opt.get().identifier();
|
||||
} else if (opt.filter(c -> (c != null) && c.verify("p4ssw0rd-special")).isPresent()) {
|
||||
if (isCheck) return null;
|
||||
else return opt.get().identifier() + "-admin";
|
||||
} else {
|
||||
throw noMatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateBasicPF("secure site", myUserPassAuthenticator, userName ->
|
||||
complete("The user is '" + userName + "'")
|
||||
)
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/secured"))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The resource requires authentication, which was not supplied with the request")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertEntity("The user is 'John'");
|
||||
|
||||
final HttpCredentials validAdminCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd-special");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validAdminCredentials))
|
||||
.assertEntity("The user is 'John-admin'");
|
||||
|
||||
final HttpCredentials invalidCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(invalidCredentials))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The supplied authentication is invalid")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
//#authenticateBasicPF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateBasicPFAsync() {
|
||||
//#authenticateBasicPFAsync
|
||||
class User {
|
||||
private final String id;
|
||||
public User(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
final PartialFunction<Optional<ProvidedCredentials>, CompletionStage<User>> myUserPassAuthenticator =
|
||||
new JavaPartialFunction<Optional<ProvidedCredentials>,CompletionStage<User>>() {
|
||||
@Override
|
||||
public CompletionStage<User> apply(Optional<ProvidedCredentials> opt, boolean isCheck) throws Exception {
|
||||
if (opt.filter(c -> (c != null) && c.verify("p4ssw0rd")).isPresent()) {
|
||||
if (isCheck) return CompletableFuture.completedFuture(null);
|
||||
else return CompletableFuture.completedFuture(new User(opt.get().identifier()));
|
||||
} else {
|
||||
throw noMatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateBasicPFAsync("secure site", myUserPassAuthenticator, user ->
|
||||
complete("The user is '" + user.getId() + "'"))
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/secured"))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The resource requires authentication, which was not supplied with the request")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertEntity("The user is 'John'");
|
||||
|
||||
final HttpCredentials invalidCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(invalidCredentials))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The supplied authentication is invalid")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
//#authenticateBasicPFAsync
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateBasicAsync() {
|
||||
//#authenticateBasicAsync
|
||||
final Function<Optional<ProvidedCredentials>, CompletionStage<Optional<String>>> myUserPassAuthenticator = opt -> {
|
||||
if (opt.filter(c -> (c != null) && c.verify("p4ssw0rd")).isPresent()) {
|
||||
return CompletableFuture.completedFuture(Optional.of(opt.get().identifier()));
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(Optional.empty());
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateBasicAsync("secure site", myUserPassAuthenticator, userName ->
|
||||
complete("The user is '" + userName + "'")
|
||||
)
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/secured"))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The resource requires authentication, which was not supplied with the request")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertEntity("The user is 'John'");
|
||||
|
||||
final HttpCredentials invalidCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(invalidCredentials))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The supplied authentication is invalid")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
//#authenticateBasicAsync
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateOrRejectWithChallenge() {
|
||||
//#authenticateOrRejectWithChallenge
|
||||
final HttpChallenge challenge = HttpChallenge.create("MyAuth", "MyRealm");
|
||||
|
||||
// your custom authentication logic:
|
||||
final Function<HttpCredentials, Boolean> auth = credentials -> true;
|
||||
|
||||
final Function<Optional<HttpCredentials>, CompletionStage<Either<HttpChallenge, String>>> myUserPassAuthenticator =
|
||||
opt -> {
|
||||
if (opt.isPresent() && auth.apply(opt.get())) {
|
||||
return CompletableFuture.completedFuture(Right.apply("some-user-name-from-creds"));
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(Left.apply(challenge));
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateOrRejectWithChallenge(myUserPassAuthenticator, userName ->
|
||||
complete("Authenticated!")
|
||||
)
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
testRoute(route).run(HttpRequest.GET("/secured"))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The resource requires authentication, which was not supplied with the request")
|
||||
.assertHeaderExists("WWW-Authenticate", "MyAuth realm=\"MyRealm\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertStatusCode(StatusCodes.OK)
|
||||
.assertEntity("Authenticated!");
|
||||
//#authenticateOrRejectWithChallenge
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthorize() {
|
||||
//#authorize
|
||||
class User {
|
||||
private final String name;
|
||||
public User(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// authenticate the user:
|
||||
final Function<Optional<ProvidedCredentials>, Optional<User>> myUserPassAuthenticator =
|
||||
opt -> {
|
||||
if (opt.isPresent()) {
|
||||
return Optional.of(new User(opt.get().identifier()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
|
||||
// check if user is authorized to perform admin actions:
|
||||
final Set<String> admins = new HashSet<>();
|
||||
admins.add("Peter");
|
||||
final Function<User, Boolean> hasAdminPermissions = user -> admins.contains(user.getName());
|
||||
|
||||
final Route route = authenticateBasic("secure site", myUserPassAuthenticator, user ->
|
||||
path("peters-lair", () ->
|
||||
authorize(() -> hasAdminPermissions.apply(user), () ->
|
||||
complete("'" + user.getName() +"' visited Peter's lair")
|
||||
)
|
||||
)
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
final HttpCredentials johnsCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(johnsCred))
|
||||
.assertStatusCode(StatusCodes.FORBIDDEN)
|
||||
.assertEntity("The supplied authentication is not authorized to access this resource");
|
||||
|
||||
final HttpCredentials petersCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(petersCred))
|
||||
.assertEntity("'Peter' visited Peter's lair");
|
||||
//#authorize
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthorizeAsync() {
|
||||
//#authorizeAsync
|
||||
class User {
|
||||
private final String name;
|
||||
public User(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// authenticate the user:
|
||||
final Function<Optional<ProvidedCredentials>, Optional<User>> myUserPassAuthenticator =
|
||||
opt -> {
|
||||
if (opt.isPresent()) {
|
||||
return Optional.of(new User(opt.get().identifier()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
|
||||
// check if user is authorized to perform admin actions,
|
||||
// this could potentially be a long operation so it would return a Future
|
||||
final Set<String> admins = new HashSet<>();
|
||||
admins.add("Peter");
|
||||
final Set<String> synchronizedAdmins = Collections.synchronizedSet(admins);
|
||||
|
||||
final Function<User, CompletionStage<Object>> hasAdminPermissions =
|
||||
user -> CompletableFuture.completedFuture(synchronizedAdmins.contains(user.getName()));
|
||||
|
||||
final Route route = authenticateBasic("secure site", myUserPassAuthenticator, user ->
|
||||
path("peters-lair", () ->
|
||||
authorizeAsync(() -> hasAdminPermissions.apply(user), () ->
|
||||
complete("'" + user.getName() +"' visited Peter's lair")
|
||||
)
|
||||
)
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
final HttpCredentials johnsCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(johnsCred))
|
||||
.assertStatusCode(StatusCodes.FORBIDDEN)
|
||||
.assertEntity("The supplied authentication is not authorized to access this resource");
|
||||
|
||||
final HttpCredentials petersCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(petersCred))
|
||||
.assertEntity("'Peter' visited Peter's lair");
|
||||
//#authorizeAsync
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractCredentials() {
|
||||
//#extractCredentials
|
||||
final Route route = extractCredentials(optCreds -> {
|
||||
if (optCreds.isPresent()) {
|
||||
return complete("Credentials: " + optCreds.get());
|
||||
} else {
|
||||
return complete("No credentials");
|
||||
}
|
||||
});
|
||||
|
||||
// tests:
|
||||
final HttpCredentials johnsCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/").addCredentials(johnsCred))
|
||||
.assertEntity("Credentials: Basic Sm9objpwNHNzdzByZA==");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("No credentials");
|
||||
//#extractCredentials
|
||||
}
|
||||
}
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
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.HttpRequest;
|
||||
import akka.http.javadsl.model.HttpResponse;
|
||||
import akka.http.javadsl.model.StatusCode;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.server.AllDirectives;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.scaladsl.TestUtils;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.testkit.TestKit;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import scala.Tuple2;
|
||||
import scala.Tuple3;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import scala.runtime.BoxedUnit;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class TimeoutDirectivesExamplesTest extends AllDirectives {
|
||||
//#testSetup
|
||||
private final Config testConf = ConfigFactory.parseString("akka.loggers = [\"akka.testkit.TestEventListener\"]\n"
|
||||
+ "akka.loglevel = ERROR\n"
|
||||
+ "akka.stdout-loglevel = ERROR\n"
|
||||
+ "windows-connection-abort-workaround-enabled = auto\n"
|
||||
+ "akka.log-dead-letters = OFF\n"
|
||||
+ "akka.http.server.request-timeout = 1000s");
|
||||
// large timeout - 1000s (please note - setting to infinite will disable Timeout-Access header
|
||||
// and withRequestTimeout will not work)
|
||||
|
||||
private final ActorSystem system = ActorSystem.create("TimeoutDirectivesExamplesTest", testConf);
|
||||
|
||||
private final ActorMaterializer materializer = ActorMaterializer.create(system);
|
||||
|
||||
private final Http http = Http.get(system);
|
||||
|
||||
private CompletionStage<Void> shutdown(CompletionStage<ServerBinding> binding) {
|
||||
return binding.thenAccept(b -> {
|
||||
System.out.println(String.format("Unbinding from %s", b.localAddress()));
|
||||
|
||||
final CompletionStage<BoxedUnit> unbound = b.unbind();
|
||||
try {
|
||||
unbound.toCompletableFuture().get(3, TimeUnit.SECONDS); // block...
|
||||
} catch (TimeoutException | InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<HttpResponse> runRoute(ActorSystem system, ActorMaterializer materializer, Route route, String routePath) {
|
||||
final Tuple3<InetSocketAddress, String, Object> inetaddrHostAndPort = TestUtils.temporaryServerHostnameAndPort("127.0.0.1");
|
||||
Tuple2<String, Integer> hostAndPort = new Tuple2<>(
|
||||
inetaddrHostAndPort._2(),
|
||||
(Integer) inetaddrHostAndPort._3()
|
||||
);
|
||||
|
||||
final Flow<HttpRequest, HttpResponse, NotUsed> routeFlow = route.flow(system, materializer);
|
||||
final CompletionStage<ServerBinding> binding = http.bindAndHandle(routeFlow, ConnectHttp.toHost(hostAndPort._1(), hostAndPort._2()), materializer);
|
||||
|
||||
final CompletionStage<HttpResponse> responseCompletionStage = http.singleRequest(HttpRequest.create("http://" + hostAndPort._1() + ":" + hostAndPort._2() + "/" + routePath), materializer);
|
||||
|
||||
CompletableFuture<HttpResponse> responseFuture = responseCompletionStage.toCompletableFuture();
|
||||
|
||||
Optional<HttpResponse> responseOptional;
|
||||
try {
|
||||
responseOptional = Optional.of(responseFuture.get(3, TimeUnit.SECONDS)); // patienceConfig
|
||||
} catch (Exception e) {
|
||||
responseOptional = Optional.empty();
|
||||
}
|
||||
|
||||
shutdown(binding);
|
||||
|
||||
return responseOptional;
|
||||
}
|
||||
//#
|
||||
|
||||
@After
|
||||
public void shutDown() {
|
||||
TestKit.shutdownActorSystem(system, Duration.create(1, TimeUnit.SECONDS), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestTimeoutIsConfigurable() {
|
||||
//#withRequestTimeout-plain
|
||||
final Duration timeout = Duration.create(1, TimeUnit.SECONDS);
|
||||
CompletionStage<String> slowFuture = new CompletableFuture<>();
|
||||
|
||||
final Route route = path("timeout", () ->
|
||||
withRequestTimeout(timeout, () -> {
|
||||
return completeOKWithFutureString(slowFuture); // very slow
|
||||
})
|
||||
);
|
||||
|
||||
// test:
|
||||
StatusCode statusCode = runRoute(system, materializer, route, "timeout").get().status();
|
||||
assert (StatusCodes.SERVICE_UNAVAILABLE.equals(statusCode));
|
||||
//#
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestWithoutTimeoutCancelsTimeout() {
|
||||
//#withoutRequestTimeout-1
|
||||
CompletionStage<String> slowFuture = new CompletableFuture<>();
|
||||
|
||||
final Route route = path("timeout", () ->
|
||||
withoutRequestTimeout(() -> {
|
||||
return completeOKWithFutureString(slowFuture); // very slow
|
||||
})
|
||||
);
|
||||
|
||||
// test:
|
||||
Boolean receivedReply = runRoute(system, materializer, route, "timeout").isPresent();
|
||||
assert (!receivedReply); // timed-out
|
||||
//#
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestTimeoutAllowsCustomResponse() {
|
||||
//#withRequestTimeout-with-handler
|
||||
final Duration timeout = Duration.create(1, TimeUnit.MILLISECONDS);
|
||||
CompletionStage<String> slowFuture = new CompletableFuture<>();
|
||||
|
||||
HttpResponse enhanceYourCalmResponse = HttpResponse.create()
|
||||
.withStatus(StatusCodes.ENHANCE_YOUR_CALM)
|
||||
.withEntity("Unable to serve response within time limit, please enhance your calm.");
|
||||
|
||||
final Route route = path("timeout", () ->
|
||||
withRequestTimeout(timeout, (request) -> enhanceYourCalmResponse, () -> {
|
||||
return completeOKWithFutureString(slowFuture); // very slow
|
||||
})
|
||||
);
|
||||
|
||||
// test:
|
||||
StatusCode statusCode = runRoute(system, materializer, route, "timeout").get().status();
|
||||
assert (StatusCodes.ENHANCE_YOUR_CALM.equals(statusCode));
|
||||
//#
|
||||
}
|
||||
|
||||
// make it compile only to avoid flaking in slow builds
|
||||
@Ignore("Compile only test")
|
||||
@Test
|
||||
public void testRequestTimeoutCustomResponseCanBeAddedSeparately() {
|
||||
//#withRequestTimeoutResponse
|
||||
final Duration timeout = Duration.create(100, TimeUnit.MILLISECONDS);
|
||||
CompletionStage<String> slowFuture = new CompletableFuture<>();
|
||||
|
||||
HttpResponse enhanceYourCalmResponse = HttpResponse.create()
|
||||
.withStatus(StatusCodes.ENHANCE_YOUR_CALM)
|
||||
.withEntity("Unable to serve response within time limit, please enhance your calm.");
|
||||
|
||||
final Route route = path("timeout", () ->
|
||||
withRequestTimeout(timeout, () ->
|
||||
// racy! for a very short timeout like 1.milli you can still get 503
|
||||
withRequestTimeoutResponse((request) -> enhanceYourCalmResponse, () -> {
|
||||
return completeOKWithFutureString(slowFuture); // very slow
|
||||
}))
|
||||
);
|
||||
|
||||
// test:
|
||||
StatusCode statusCode = runRoute(system, materializer, route, "timeout").get().status();
|
||||
assert (StatusCodes.ENHANCE_YOUR_CALM.equals(statusCode));
|
||||
//#
|
||||
}
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.model.headers.SecWebSocketProtocol;
|
||||
import akka.http.javadsl.model.ws.BinaryMessage;
|
||||
import akka.http.javadsl.model.ws.Message;
|
||||
import akka.http.javadsl.model.ws.TextMessage;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.WSProbe;
|
||||
import akka.stream.OverflowStrategy;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Sink;
|
||||
import akka.stream.javadsl.Source;
|
||||
import akka.util.ByteString;
|
||||
import org.junit.Test;
|
||||
import scala.concurrent.duration.FiniteDuration;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class WebSocketDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testHandleWebSocketMessages() {
|
||||
//#handleWebSocketMessages
|
||||
final Flow<Message, Message, NotUsed> greeter = Flow.of(Message.class).mapConcat(msg -> {
|
||||
if (msg instanceof TextMessage) {
|
||||
final TextMessage tm = (TextMessage) msg;
|
||||
final TextMessage ret = TextMessage.create(Source.single("Hello ").concat(tm.getStreamedText()).concat(Source.single("!")));
|
||||
return Collections.singletonList(ret);
|
||||
} else if (msg instanceof BinaryMessage) {
|
||||
final BinaryMessage bm = (BinaryMessage) msg;
|
||||
bm.getStreamedData().runWith(Sink.ignore(), materializer());
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported message type!");
|
||||
}
|
||||
});
|
||||
|
||||
final Route websocketRoute = path("greeter", () ->
|
||||
handleWebSocketMessages(greeter)
|
||||
);
|
||||
|
||||
// create a testing probe representing the client-side
|
||||
final WSProbe wsClient = WSProbe.create(system(), materializer());
|
||||
|
||||
// WS creates a WebSocket request for testing
|
||||
testRoute(websocketRoute).run(WS(Uri.create("/greeter"), wsClient.flow(), materializer()))
|
||||
.assertStatusCode(StatusCodes.SWITCHING_PROTOCOLS);
|
||||
|
||||
// manually run a WS conversation
|
||||
wsClient.sendMessage("Peter");
|
||||
wsClient.expectMessage("Hello Peter!");
|
||||
|
||||
wsClient.sendMessage(BinaryMessage.create(ByteString.fromString("abcdef")));
|
||||
wsClient.expectNoMessage(FiniteDuration.create(100, TimeUnit.MILLISECONDS));
|
||||
|
||||
wsClient.sendMessage("John");
|
||||
wsClient.expectMessage("Hello John!");
|
||||
|
||||
wsClient.sendCompletion();
|
||||
wsClient.expectCompletion();
|
||||
//#handleWebSocketMessages
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleWebSocketMessagesForProtocol() {
|
||||
//#handleWebSocketMessagesForProtocol
|
||||
final Flow<Message, Message, NotUsed> greeterService = Flow.of(Message.class).mapConcat(msg -> {
|
||||
if (msg instanceof TextMessage) {
|
||||
final TextMessage tm = (TextMessage) msg;
|
||||
final TextMessage ret = TextMessage.create(Source.single("Hello ").concat(tm.getStreamedText()).concat(Source.single("!")));
|
||||
return Collections.singletonList(ret);
|
||||
} else if (msg instanceof BinaryMessage) {
|
||||
final BinaryMessage bm = (BinaryMessage) msg;
|
||||
bm.getStreamedData().runWith(Sink.ignore(), materializer());
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported message type!");
|
||||
}
|
||||
});
|
||||
|
||||
final Flow<Message, Message, NotUsed> echoService = Flow.of(Message.class).buffer(1, OverflowStrategy.backpressure());
|
||||
|
||||
final Route websocketMultipleProtocolRoute = path("services", () ->
|
||||
route(
|
||||
handleWebSocketMessagesForProtocol(greeterService, "greeter"),
|
||||
handleWebSocketMessagesForProtocol(echoService, "echo")
|
||||
)
|
||||
);
|
||||
|
||||
// create a testing probe representing the client-side
|
||||
final WSProbe wsClient = WSProbe.create(system(), materializer());
|
||||
|
||||
// WS creates a WebSocket request for testing
|
||||
testRoute(websocketMultipleProtocolRoute)
|
||||
.run(WS(Uri.create("/services"), wsClient.flow(), materializer(), Arrays.asList("other", "echo")))
|
||||
.assertHeaderExists(SecWebSocketProtocol.create("echo"));
|
||||
|
||||
wsClient.sendMessage("Peter");
|
||||
wsClient.expectMessage("Peter");
|
||||
|
||||
wsClient.sendMessage(BinaryMessage.create(ByteString.fromString("abcdef")));
|
||||
wsClient.expectMessage(ByteString.fromString("abcdef"));
|
||||
|
||||
wsClient.sendMessage("John");
|
||||
wsClient.expectMessage("John");
|
||||
|
||||
wsClient.sendCompletion();
|
||||
wsClient.expectCompletion();
|
||||
//#handleWebSocketMessagesForProtocol
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.testkit;
|
||||
|
||||
//#simple-app
|
||||
|
||||
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.unmarshalling.StringUnmarshallers;
|
||||
import akka.http.javadsl.server.examples.simple.SimpleServerApp;
|
||||
import akka.stream.ActorMaterializer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
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
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.http.javadsl.server.testkit;
|
||||
|
||||
//#simple-app-testing
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestkitExampleTest extends JUnitRouteTest {
|
||||
TestRoute appRoute = testRoute(new MyAppService().createRoute());
|
||||
|
||||
@Test
|
||||
public void testCalculatorAdd() {
|
||||
// test happy path
|
||||
appRoute.run(HttpRequest.GET("/calculator/add?x=4.2&y=2.3"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("x + y = 6.5");
|
||||
|
||||
// test responses to potential errors
|
||||
appRoute.run(HttpRequest.GET("/calculator/add?x=3.2"))
|
||||
.assertStatusCode(StatusCodes.NOT_FOUND) // 404
|
||||
.assertEntity("Request is missing required query parameter 'y'");
|
||||
|
||||
// test responses to potential errors
|
||||
appRoute.run(HttpRequest.GET("/calculator/add?x=3.2&y=three"))
|
||||
.assertStatusCode(StatusCodes.BAD_REQUEST)
|
||||
.assertEntity("The query parameter 'y' was malformed:\n" +
|
||||
"'three' is not a valid 64-bit floating point value");
|
||||
}
|
||||
}
|
||||
//#simple-app-testing
|
||||
Loading…
Add table
Add a link
Reference in a new issue