Documentation

You are viewing the documentation for Play 1. The documentation for Play 2 is here.

HTTP ルーティング

Router は、送り込まれた HTTP リクエストをアクション (コントローラの static で public なメソッド) の呼び出しに対応付けるコンポーネントです。

HTTP リクエストは MVC フレームワークにおいてイベントと見なされます。このイベントは 2 つの主要な情報を含んでいます:

REST について

REST (Representational state transfer) は、World Wide Web などの分散ハイパーメディアシステムのためのソフトウェアアーキテクチャスタイルです。

REST が述べるいくつかの主要な設計原理は以下の通りです:

HTTP を使用する場合は、インタフェースは利用可能な HTTP メソッドのセットとして定義されます。 リソース状態にアクセスするために使用されるプロトコルは、以下の通りです:

アプリケーションが主な REST 設計原理に従うなら、そのアプリケーションは RESTful です。Play フレームワークを使うと、容易に RESTful アプリケーションを構築することができます:

routes ファイルの構文

conf/routes ファイルは、Router が使用する設定ファイルです。このファイルはアプリケーションに必要なすべてのルートを記載します。各ルートは Java 呼び出しに関連付けられた HTTP メソッド + URI パターンで構成されます。

ルート定義がどのようなものか見てみましょう:

GET    /clients/{id}             Clients.show           

各ルートは HTTP メソッドから始まり、URI パターンが続きます。ルーティングの最後の要素は Java 呼び出しの定義です。

"#" 文字でルートファイルにコメントを追加できます。

# Display a client
GET    /clients/{id}             Clients.show           

HTTP メソッド

HTTPによってサポートされてる有効なメソッドのうち、いずれかひとつをルートの HTTP メソッドに指定することができます:

HTTP メソッドに * を指定した場合、このルートはどのようなメソッドの HTTP リクエストにもマッチします。

*   /clients/{id}             Clients.show           

このルートは以下のいずれにも適合します:

GET /clients/1541
PUT /clients/1212

URI パターン

URI パターンはルートのリクエストパスを定義します。ルートの一部を動的に定義することが可能です。動的部分はすべて 中括弧 {…} の中に指定しなければいけません。

/clients/all

完全にマッチします:

/clients/all

しかし …

/clients/{id}

これらについてもそれぞれマッチします:

/clients/12121
/clients/toto

URI パターンにはより多くの動的な部分があるかもしれません:

/clients/{id}/accounts/{accountId}

動的部分のデフォルトのマッチング方式は、正規表現 /[^/]+/ として定義されています。動的部分の正規表現を独自に定義することができます。

この正規表現は id に数値のみを許可します:

/clients/{<[0-9]+>id}

これは id が 4~10 文字の小文字だけを含む単語であることを保証します:

/clients/{<[a-z]{4,10}>id}

ここではどのような正規表現も使用することができます。

注意

動的部分には名前が付けられます。コントローラは後から HTTP パラメータの Map から動的部分を検索することができます。

デフォルトで、Play は URL のあとに続くスラッシュを重要視します。例えば次のようなルートの場合:

GET     /clients         Clients.index

/clients という URL にはマッチしますが、 /clients/ にはマッチしません。スラッシュの後にクエスチョンマークを追加することで、Play に両方の URL にマッチするよう伝えることができます。例えば、次のようにします:

GET     /clients/?       Clients.index

この URI パターンは、最後のスラッシュ以外にはどのような追加部分も持つことはできません。

Java の呼び出し定義

ルート定義の最後の部分は Java 呼び出しです。この部分はアクションメソッドの完全修飾名で定義されます。アクションメソッドは Controller クラスの public static void なメソッドでなければいけません。Controller クラスは controllers パッケージに定義しなければならず、また、 play.mvc.Controller のサブクラスでなければいけません。

コントローラが controllers パッケージの直下に定義されていない場合は、クラス名の前に Java パッケージ名を追記することができます。 controllers パッケージ自体は暗黙的なので、特に指定する必要はありません。

GET    /admin             admin.Dashboard.index           

静的引数の割り当て

ある場合においては、アクションは再利用しても、いくつかの引数の値に基づいてより特別なルートを定義したいことがあります。

これがどのようなものか、以下の例を見てみましょう:

public static void page(String id) {
    Page page = Page.findById(id);
    render(page);
}

対応するルートは次のとおりです:

GET    /pages/{id}        Application.page

ここで、このページに ‘home’ という ID で別名を定義したいと思います。静的引数を使って別のルートを定義することができます:

GET    /home              Application.page(id:'home')
GET    /pages/{id}        Application.page

最初のルートは、ページの id が ‘home’ である場合、2 番目のルートと等価です。しかし、最初のルートはより高い優先度を持つので、id が ‘home’ である Application.page 呼び出しのデフォルト定義として使用されます。

ルーティングの優先順位

複数のルートが同じリクエストにマッチすることができます。競合がある場合は、(宣言した順番に従い) 最初のルートが使用されます。

例えば:

GET    /clients/all       Clients.listAll
GET    /clients/{id}      Clients.show

これらの定義において、URI が次のとおりである場合:

/clients/all

(2 番目のルートもリクエストにマッチするとしても) 最初のルートが適用されて、Clients.listAll をコールします。

静的リソースの配信

静的なリソースのコンテナとして公開したい場合、各フォルダを特別なアクション staticDir を使って示してください。

例えば:

GET    /public/           staticDir:public

/public/* パスに対するリクエストがあった場合、Play はアプリケーションの /public フォルダからファイルを配信します。

優先度は通常のルートと同じように適用されます。

リバースルーティング : URL の生成

Java 呼び出し中に URL を生成するのに Router が使用できます。このため、すべての URI をただひとつの設定ファイルに集約することが可能であり、より自信をもってアプリケーションをリファクタリングすることができます。

例えば、次のようなルート定義において:

GET    /clients/{id}      Clients.show

Clients.show を起動することができる URL を、コードから生成することができます:

map.put("id", 1541);
String url = Router.reverse("Clients.show", map).url;  // GET /clients/1541

この URL 生成機能はフレームワークの様々なコンポーネントに統合されています。決して Router.reverse を直接使用するべきではありません。

URI パターンに含まれていないパラメタを加えると、これらのパラメタはクエリストリングに追加されます:

map.put("id", 1541);
map.put("display", "full");
String url = Router.reverse("Clients.show", map).url; // GET /clients/1541?display=full

URL を生成するもっとも特別なルートを見つけるため、優先順位が再度使用されます。

content type の設定

Play は request.format に従って HTTP レスポンスの メディアタイプ を選択します。この値は、どの view テンプレートを使用するかをファイル拡張子によって決定し、また Play の mime-types.properties ファイルがこのフォーマットにマッピングするメディアタイプを、レスポンスの Content-type に設定します。

Play に対するリクエストのデフォルトフォーマットは html です。そのため、コントローラの index() メソッド (そして html フォーマット) に対するデフォルトのテンプレートは index.html です。もし違うフォーマットを指定する場合、いくつかある方法のひとつとして、代替テンプレートを選択することができます。

render メソッドを呼び出す前に、このフォーマットをプログラム上から設定することができます。例えば、 text/css メディアタイプと共に CSS を提供する場合、次のように設定します:

request.format = "css";  

一方、 routes ファイルにおいて URL を使ってフォーマットを指定する、よりきれいなアプローチもあります。コントローラのメソッドにフォーマットを指定することで、特定のルートにフォーマットを追加することができます。例えば、以下のルートは /index.xml に対するリクエストをハンドリングし、フォーマットを xml に設定し、 index.xml テンプレートをレンダリングします。

GET    /index.xml         Application.index(format:'xml')  

同様に:

GET    /stylesheets/dynamic_css   css.SiteCSS(format:'css')

Play は、以下のルートのように、URL から直接フォーマットを抽出することもできます。

GET    /index.{format}    Application.index 

このルートでは、 index.xml に対するリクエストには xml がフォーマットに設定されて XML テンプレートがレンダリングされますが、 index.txt に対するリクエストにはプレーンテキストのテンプレートがレンダリングされます。

Play は HTTP コンテントネゴシエーションを使って自動的にフォーマットを設定することもできます。

HTTP コンテントネゴシエーション

Play が他の RESTful アーキテクチャと共通していることのうちのひとつは、HTTP を隠そうとしたり、HTTP の上に抽象層を置こうとしたりせず、HTTP の機能を直接使用するということです。コンテントネゴシエーション は、HTTP サーバが、HTTP クライアントによりリクエストされたメディアタイプに従って、同じ URL に対して異なる メディアタイプ を提供できるようにする HTTP の機能です。クライアントは、例えば XML レスポンスを要求する場合、以下のように Accept ヘッダを使って受信できるコンテントタイプを指定します:

Accept: application/xml

クライアントはひとつ以上のメディアタイプを指定するかもしれませんし、ワイルドカード (*/*) を使用して、どのようなメディアタイプも受信できると指定するかもしれません:

Accept: application/xml, image/png, */*

古臭い web ブラウザは、どのようなメディアタイプでも受信しようと Accept ヘッダにいつでもワイルドカードを含めます: そして Play は HTML を - デフォルトの ‘フォーマット’ として提供します。コンテントネゴシエーションは JSON レスポンスを要求する Ajax リクエストや、PDF や EPUB バージョンのドキュメントを要求する e-book リーダのような、カスタマイズされたクライアントにおいて、より頻繁に利用されるでしょう。

HTTP ヘッダによるコンテントタイプの設定

Accept ヘッダに text/htmlapplication/xhtml が含まれる場合、または ワイルドカード */* が指定されている場合、Play はデフォルトのリクエストフォーマットである html を選択します。ワイルドカード値が存在しない場合はデフォルトフォーマットは選択されません。

Play はいくつかのフォーマット: html, txt, jsonxml を組み込みでサポートします。例えば、いくつかのデータをレンダリングするコントローラメソッドを定義します:

public static void index() { 
   final String name = "Peter Hilton"; 
   final String organisation = "Lunatech Research"; 
   final String url = "http://www.lunatech-research.com/"; 
   render(name, organisation, url); 
} 

このメソッドにマッピングされた URL (新しい Play アプリケーションの場合は http://localhost:9000/) を web ブラウザからリクエストすると、web ブラウザは値に text/html を含む Accept ヘッダを送信するので、Play は index.html テンプレートをレンダリングします。

Play は、リクエストフォーマットに xml を設定し、例えば以下のような index.xml テンプレートをレンダリングすることで、 Accept: text/xml ヘッダを含むリクエストに応答します:

<?xml version="1.0"?> 
<contact> 
<name>${name}</name> 
<organisation>${organisation}</organisation> 
<url>${url}</url> 
</contact> 

index() コントローラメソッドに対する組み込みの Accept ヘッダとフォーマットのマッピングは下記のように動作します: accept ヘッダは、Play がやがてはテンプレートファイルに紐付けられることになるフォーマットにマッピングしたメディアタイプを含みます。

Accept header Format Template file name Mapping
null null index.html null フォーマットに対するデフォルトのテンプレート拡張
image/png null index.html フォーマットにマッピングされないメディアタイプ
*/*, image/png html index.html html フォーマットにマッピングされるデフォルトのメディアタイプ
text/html html index.html 組み込みフォーマット
application/xhtml html index.html 組み込みフォーマット
text/xml xml index.xml 組み込みフォーマット
application/xml xml index.xml 組み込みフォーマット
text/plain txt index.txt 組み込みフォーマット
text/javascript json index.json 組み込みフォーマット
application/json, */* json index.json デフォルトのメディアタイプを無視する組み込みフォーマット

カスタムフォーマット

HTTP リクエストが対応するメディアタイプを選択する場合にのみ、リクエストヘッダを調査し、それに従ってフォーマットを設定し、独自のメディアタイプについてコンテントネゴシエーションを追加することができます。例えば、vCardtext/x-vcard メディアタイプと共に提供するには、コントローラにて全てのリクエストの前に独自のフォーマッとチェックを行います:

@Before 
static void setFormat() { 
	if (request.headers.get("accept").value().equals("text/x-vcard")) { 
		request.format = "vcf"; 
	} 
} 

これで、 Accept: text/x-vcard を含むリクエストは、以下のような index.vcf テンプレートをレンダリングするようになります:

BEGIN:VCARD 
VERSION:3.0 
N:${name} 
FN:${name} 
ORG:${organisation} 
URL:${url} 
END:VCARD  

考察を続けます

Router が受け取った HTTP リクエストによって起動する Java 呼び出しを決定したら、Play フレームワークはその Java 呼び出しを起動します。 コントローラ がどのように動作するのかを見てみましょう。