ルーティングDSLの概要
Akka HTTP 低レベルサーバーサイドAPI は、アプリケーションが受信したHTTPリクエストを簡単にレスポンスにマッピングする為の Flow``若しくは ``Function
レベルのインターフェースを提供しています。 ( Low-level server side example から抜粋。)
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;
}
}
};
受信した HttpRequest
に対してパターンマッチを使った完璧なREST APIを完全に定義する事が可能ですが、このアプローチは大量の文法の"儀式"を必要とし、比較的大きなサービスにはいくらか扱いにくくなってしまいます。また、サービスの定義をあなたが好む DRY に保つのに役に立ちません。
Akka HTTPはその代わりとして、あなたのサービスの振る舞いを簡潔で読みやすく記述できる要素の構造( ディレクティブ と呼ばれています)として表現できる柔軟なDSLを提供しています。ディレクティブは トップレベルにおいて bind
を呼ぶ事で直接供給される Flow
処理 (若しくは、非同期な処理関数)で構成されるルート構造体として組み上げられます。
構成可能な高レベルAPIによって書き直された完全な例を次に示します。
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
)
));
}
}
ルーティングDSLのコアは、一つのインポートで有効になります。
import akka.http.javadsl.server.Directives.*;
また、全てのディレクティブを一つのクラスにまとめてアクセスしやすくする akka.http.javadsl.server.AllDirectives
を拡張することによって
extends AllDirectives
もちろん、必要なディレクティブのみ (例えば、WebSocketDirectives
など) をインポートすることも可能です。
Contents