ルート

ルート

"Route" はAkka HTTPのルーティングDSLにおいて中心となる概念です。DSLで構築した構造体は、それが一行で構成されていても数百行で構成されていてもこの型のインスタンスになります。

type Route = RequestContext  Future[RouteResult]

これは RequestContextFuture[RouteResult] に変換する関数の単純なエイリアスです。

全般的に、ルートがリクエストを受信すると(若しくは、そのための RequestContext を受け取ると)、これらうち一つを実行する事が出来ます。

  • requestContext.complete(...) の値を返すことによってリクエストを完了する。

  • requestContext.reject(...) の値を返すことによって、リクエストを拒否します。 ( Rejections を参照して下さい。)

  • requestContext.fail(...) の値を返す、若しくは単純に例外を投げることによって、リクエストを失敗させます。 ( Exception Handling を参照して下さい。)

  • あらゆる非同期処理を行い、後で完了する処理は Future[RouteResult] として直ぐに返します。

前者のケースはかなり明確であり、 complete を呼ぶことによって、クライアントにリクエストの応答としてのレスポンスを返すケースです。後者のケースの "reject" はルートが処理を継続したくない場合を意味しています。以下の節では、ルートの構成として、これらが何に適しているのかを詳しく説明します。

RouteRoute.seal を使うことによって、 "sealed" とする事ができます。これらはスコープ内の RejectionHandlerExceptionHandler のインスタンスを使って、リジェクションと例外をクライアントに返す明確なHTTPレスポンスに変換します。

Route.handlerFlowRoute.asyncHandler 又は Route を使用する事によって、 低レベルサーバーサイドAPI から呼ばれる bindAndHandleXXX と共に使用する Flow や非同期な処理関数に引き上げる事が出来ます。

注記: Route から Flow[HttpRequest, HttpResponse, Unit] への暗黙的な変換が Route.handlerFlow に依存する RouteResult のコンパニオンオブジェクトに定義されています。

リクエストコンテキスト

リクエストコンテキストは HttpRequest インスタンスに、 ExecutionContextMaterializer`` 、 ``LoggingAdapter や設定された RoutingSettings などの典型的なルーティング処理に必要とされる情報を付加し、その機能を高めます。また、これには Path Directive にマッチしていないリクエストURIの数の値を持つ unmatchedPath も含まれています。

RequestContext 自体は不変ですが、利便性の為に、変更されたコピーを生成する幾つかのヘルパーメソッドが提供されています。

ルートリザルト

RouteResultRoute のエラーではない結果をモデルとした、シンプルな抽象データ型(ADT)です。次のように定義されます:

sealed trait RouteResult

object RouteResult {
  final case class Complete(response: HttpResponse) extends RouteResult
  final case class Rejected(rejections: immutable.Seq[Rejection]) extends RouteResult
}

通常は RouteResult をあなた自身で作成するのではなく、事前に定義された RouteDirectives ( completereject 若しくは redirect ) に依存するか、それぞれのメソッドを リクエストコンテキスト に置き換えて下さい。

ルートを組み立てる

一から複雑なルートを構築する為に必要な三つの基本的な操作があります。

  • 別の内部的なルートに処理を委譲し、受信したリクエスト、送信されたレスポンス、若しくはその両方のプロパティの一部が変更するルートの変換

  • 条件を満たすリクエストのみを通過させ、他のリクエストは全て拒否するルートのフィルタリング

  • 最初のルートが拒否された時に次のルートを試行するルートの連鎖

最後のポイントは結合演算子 ~ で実現されます。これは import akka.http.scaladsl.server.Directives._ を行なった時に有効になる拡張メソッドです。最初の二つのポイントは、所謂 ディレクティブ と呼ばれるもので提供されています。多くの ディレクティブ は Akka HTTPで事前に定義されており、また、あなた自身で簡単に作成することも出来ます。 ディレクティブ はAkka HTTPの力と柔軟性の多くを提供します。

ルーティングツリー

基本的に、ディレクティブや ~ 演算子と入れ子構造でカスタムしたルートを結合すると、ルートはツリー構造で構築されます。リクエストがこのルートのツリー構造に注入されると、リクエストはツリーの頂点から深度を優先する規則に従って、あるノードが完了、若しくは完全に拒否されるまで、全てのブランチに流れ落ちます。

この模式的な例を考えてみましょう:

val route =
  a {
    b {
      c {
        ... // route 1
      } ~
      d {
        ... // route 2
      } ~
      ... // route 3
    } ~
    e {
      ... // route 4
    }
  }

ここでは、五つのディレクティブがルーティングツリーを形成します。

  • ルート1は a, b 及び c のディレクティブが全て通過する場合にのみ到達します。

  • ルート2は、 ab を通過し、 c で拒否され d を通過した場合に実行されます。

  • ルート3は、 ab を通過し、 cd で拒否された場合に実行されます。

従って、ルート3は直前の位置で拒否された場合にのみ実行される "catch-all" ルートと見做す事が出来ます。このメカニズムにより、複雑なフィルタリングロジックを簡単に実装する事が出来ます。最も限定的なケースを前方に置き、一般的なケースを後方に置くだけです。

Contents