ルート

ルート

"Route" はAkka HTTPのルーティングDSLにおいて中心となる概念です。DSLで構築した構造体は、それが一行で構成されていても数百行で構成されていても RequestContextCompletionStage<RouteResult> に変換する関数になります。

Route それ自身は、 RequestContext を実行し RouteResult を返す関数です。 RequestContext は現在のリクエストと、リクエストがルート構造を通過した時に合致しなかったURIのパスの情報などの補助的なデータを含むデータ構造体です。このデータ構造体は現在の ExecutionContextakka.stream.Materializer も含まれています。これらを手動で持ち回る必要はありません。

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

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

  • Reject the request by returning the value of requestContext.reject(...) (see Rejections)
  • Fail the request by returning the value of requestContext.fail(...) or by just throwing an exception (see Exception Handling)
  • あらゆる非同期処理を行い、後で完了する処理は Future[RouteResult] として直ぐに返します。

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

A Route can be "sealed" using Route.seal, which relies on the in-scope RejectionHandler and ExceptionHandler instances to convert rejections and exceptions into appropriate HTTP responses for the client.

Using Route.handlerFlow or Route.asyncHandler a Route can be lifted into a handler Flow or async handler function to be used with a bindAndHandleXXX call from the 低レベルサーバーサイドAPI.

リクエストコンテキスト

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

The RequestContext itself is immutable but contains several helper methods which allow for convenient creation of modified copies.

ルートリザルト

The RouteResult is an opaque structure that represents possible results of evaluating a route. A RouteResult can only be created by using one of the methods of the RequestContext. A result can either be a response, if it was generated by one of the completeX methods, or a rejection that contains information about why the route could not handle the request.

ルートを組み立てる

ルートは二つの法則によってルートツリーとして形成されます。

ルートは "Directive" でラップする事ができ、内部のルートをラップした振る舞いを追加する事が出来ます。Java DSLにおいては、ディレクティブはRouteを返すメソッドです。多くの場合、ディレクティブのメソッドはそのセマンティクスが、例えば、URLのパスが合致した時など、ルートが実行される時に呼び出される内部のルートを持っています。

ディレクティブトピックの例

  • どのリクエストが内部のルートに到達するかを決定する為、リクエストをフィルタします。

  • 内部のルートを通過する前にリクエストを変換します。

  • 内部のルートから受け取ったレスポンス(若しくは、ルートリザルト)を変換します。

  • 内部のルートの実行にかかった時間を計測するなど、処理中の副作用を適用します。

もう一つの構成方法は、 Route のリストを定義する事です。代替えのルートは、その中の一つのルートがリクエストを受け取り、レスポンスを供給するまで試行されます。一方、ルートはリクエストを拒否することも出来、この場合はさらに別の選択肢が検討されます。代替案はルートのリストを RouteDirectives.route() に渡すことによって指定されます。

ルーティングツリー

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

この模式的な例を考えてみます。directiveAやdirectiveB、その他は、例えば、パスやヘッダ及びリクエストパラメータに合致する幾つかの有効なディレクティブとして考える事が出来ます。

import static akka.http.javadsl.server.Directives.*;

val route =
  directiveA(route(() ->
    directiveB(route(() ->
      directiveC(
        ... // route 1
      ),
      directiveD(
        ... // route 2
      ),
      ... // route 3
    )),
    directiveE(
      ... // route 4
    )
  ));

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

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

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

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

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

Contents