【翻訳】Cowboy - ルーティング

ルーティング

Cowboyはデフォルトでは何もしません

Cowboyを有効にするためには、リクエストを処理するErlangのモジュールにURLをマッピングする必要があります。
上記はルーティングと呼ばれています。

Cowboyはリクエストを受信するとディスパッチルールで定められたリソースにリクエストされたホストとパスが一致するかをチェックします。
もし一致したならば関連したErlangのコードが実行されます。

ルーティングルールはホストごとに決められています。
Cowboyは最初にホストと一致させて、それから一致するパスを見つけようとします。

Cowboyでルーティングを使用するためにはパスをコンパイルしておく必要があります。

構造

ルートの一般的な構造は以下のように定義されています。

Routes = [Host1, Host2, ... HostN].

各ホストにはオプションの制約と一緒にホスト、パスコンポーネントのためのルートのリストに対する一致するルールを含みます。

Host1 = {HostMatch, PathsList}.
Host2 = {HostMatch, Constraints, PathsList}.

パスコンポーネントのためのルートのリストは、ホストのリストに似た形で定義されます。

PathsList = [Path1, Path2, ... PathN].

最後に各経路はオプションの制約と一緒にパスの規則に一致するよう定義されており、初期化の際にオプションと一緒に使用するハンドラモジュールを定義します。

Path1 = {PathMatch, Handler, Opts}.
Path2 = {PathMatch, Constraints, Handler, Opts}.

マッチ構文とオプションの制約の詳細については下記を確認してください。

マッチ構文

マッチ構文はそれぞれのハンドラでホスト名とパスを関連付けるために使用されています。
マッチ構文はホストとパスでいくつか微妙な違いがありますが、ほぼほぼ同じです。
実際、セグメントセパレータは違いがあり、ホストが最初にアクセスするのは一番最後のセグメントから照合を始めます。
全ての例ではホストとパスが一致するルールの特徴と照合できたときの違いを説明します。

このセクションの最後にしますが特別な値を除くと最も単純な値の一致はホストまたはパスです。
これはString().やbinary().のいずれかで指定できます。

PathMatch1 = "/".
PathMatch2 = "/path/to/resource".

HostMatch1 = "cowboy.example.org".

上記で確認できますが、定義されたすべてのパスがスラッシュ文字で開始する必要があります。
ルーティングに関する限り、下記の2本のパスが同一であることに注意してください。

PathMatch2 = "/path/to/resource".
PathMatch3 = "/path/to/resource/".

末尾のドットを含まないホストはルーティングのものと同じです。
同様に先頭にドットを含まないホストも同じです。

HostMatch1 = "cowboy.example.org".
HostMatch2 = "cowboy.example.org.".
HostMatch3 = ".cowboy.example.org".

これはホストやパスのセグメントを抽出し、後で使用するために必要なオブジェクトに値を格納することが可能となるためです。
値をバインディングするためにこれらのものを呼び出します。

バインディングの構文は非常に簡単です。
セグメントの始め方:文字セグメントの端部がセグメントの値が格納されるバインディング名であることを意味します。

PathMatch = "/hats/:name/prices".
HostMatch = ":subdomain.example.org".

ルーティングするときに、これらの2つが一致してしまう場合は定義された2つのsubdomainとnameのバインディングが定義されたセグメント値を含むものとなってしまいます。

たとえばURLのhttp://test.example.org/hats/wild_cowboy_legendary/pricesサブドメインにtestとバインドされ、nameにwild_cowboy_legendaryとバインドされた値を持つこととなります。
これらは後でcowboy_req:binding/{2,3}を使用して取得することができます。
バインディング名はatomとして指定する必要があります。

Erlangでアンダースコア変数に似たような変数を使用することができる特別なバインディング名があります。
_binding に対する任意のマッチは成功しますがデータは破棄されます。
これは一度に多くのドメイン名と照合するために特に有効です。

HostMatch = "ninenines.:_".

同様に任意のセグメントを持つことが可能です。
括弧内のものはオプションです。

PathMatch = "/hats/[page/:number]".
HostMatch = "[www.]ninenines.eu".

またオプションのセグメントを重ね合わせることができます。

PathMatch = "/hats/[page/[:number]]".

[...].を使用してホストやパスの残りの部分を取得することができます。
ホストの場合には以前にマッチしたセグメントの後ろのパスの場合もマッチします。
それは1つまたは複数のセグメントを持つことができるという点で任意のセグメントが特別な場合のときです。
それぞれcowboy_req:host_info/1とcowboy_req:path_info/1を使用してセグメントを見つけることができます。
これらはセグメントのリストとして表されます。

PathMatch = "/hats/[...]".
HostMatch = "[...]ninenines.eu".

バインディングがルーティングルールで二回現れるならば、それらが同じ値を共有している場合のみマッチが成功します。
このコピーはErlangのパターンの動作と一致します。

PathMatch = "/hats/:name/:name".

任意のセグメントが存在する場合も同様です。
この場合2つの値はセグメントが使用可能である場合のみ、同一である必要があります。

PathMatch = "/hats/:name/[:name]".

ホストとパスの両方で定義されているバインディングの場合、同じ値を共有する必要があります。

PathMatch = "/:user/[...]".
HostMatch = ":user.github.com".

最後に、使用できる2つの特殊なマッチの値が存在します。
ひとつは任意のホストやパスにマッチする atom である '_'です。

PathMatch = '_'.
HostMatch = '_'.

二つ目はワイルドカードパスに一致する特別なホスト*です。
一般的にOPTIONSメソッドと一緒に使います。

HostMatch = "*".

制約

マッチングが完了した後、得られたバインディングは制約の設定に対して確認することができます。
バインディングが定義されている場合は制約のみがテストされています。
あなたが制約を定義した順序で実行します。
すべてが成功した場合のみマッチングが成功します。
常に2つ3つの要素の組として与えられます、最初の要素には結合の名前があり、二番目の要素には制約の名前があり第三の要素は任意の制約の引数です。

次の制約は、現状定義されています:

  • {Name, int}
  • {Name, function, fun ((Value) -> true | {true, NewValue} | false)}

int型の制約はバインディングが整数を表すバイナリ文字列があるかどうかを確認し、もしもある場合整数に値を変換します。

function制約は、唯一の引数としてバイナリ値を巡視、必要に応じて値をっ変換し、制約を満たすかどうかを返す必要があり、ユーザ指定された関数への結合値を渡します。
このようにして返される値は任意のタイプのものであってもよいです。

その制約関数は純粋であるべきでありクラッシュしてはいけないことに注意してください。

コンピレーション

この章で定義された構造は、Cowboyに渡される前にコンパイルされている必要があります。
これはCowboyが繰り返しルートを解析しなければならない代わりに、効率的に解析するために正しいハンドラの調べるためです。

cowboy_router:compile/1. を簡単な呼び出しで行うことができます。

Dispatch = cowboy_router:compile([
    %% {HostMatch, list({PathMatch, Handler, Opts})}
    {'_', [{'_', my_handler, []}]}
]),
%% Name, NbAcceptors, TransOpts, ProtoOpts
cowboy:start_http(my_http_listener, 100,
    [{port, 8080}],
    [{env, [{dispatch, Dispatch}]}]
).

もし指定した構造が正しくない場合、この関数が返す{error, badarg}に注意してください

ライブアップデート

ルーティングで使用されるディスパッチリストを更新するためにcowboy:set_env/3機能を使用することができます。
これはリスナーによって受け入れられ、全ての新しい接続に適用されます。

cowboy:set_env(my_http_listener, dispatch,
    cowboy_router:compile(Dispatch)).

更新する前にルートをコンパイルする必要があることに注意してください。