§HTTPルーティング
§組み込み HTTP ルータ
ルータは、クライアントから受け取った HTTP リクエストをアクションへ変換するコンポーネントです。
HTTP リクエストは MVC フレームワークにとってイベントであるといえます。このイベントには大きく分けて次の二つの情報が含まれています。
- クエリストリングを含むリクエストパス (例えば、
/clients/1542
や/photos/list
) - HTTP メソッド (GET、POST など)
ルートは conf/routes
ファイルに定義しておくことでコンパイルされます。これは、ルート定義に関するエラーもブラウザで直接的に確認できるということです。
§routes ファイルの文法
conf/routes
はルータによって読み込まれる設定ファイルです。このファイルには、アプリケーションが必要とする全てのルートをリストアップします。それぞれのルートは、HTTP メソッドと URI パターン、そしてその二つに割り当てられた Action
ジェネレータの呼び出しで表します。
実際のルート定義を見てみましょう。
GET /clients/:id controllers.Clients.show(id: Long)
それぞれのルートでは、先頭に HTTP メソッド、その後に URI パターンが続きます。最後がアクション呼び出しの定義です。
#
の文字を使って、routes ファイルにコメントを残すこともできます。
# Display a client.
GET /clients/:id controllers.Clients.show(id: Long)
§HTTP メソッド
HTTP メソッドには、HTTP がサポートするあらゆるメソッド (GET
、POST
、PUT
、DELETE
、HEAD
) が指定できます。
§URI パターン
URI パターンはルートのリクエストパスの定義です。リクエストパスの一部を動的にすることができます。
§静的パス
例えば、リクエストを GET /clients/all
に完全一致させたいときは、次のように定義できます。
GET /clients/all controllers.Clients.list()
§動的パート
しかし、URL からクライアント ID を取得するような場合には、動的パートを追加する必要があります。
GET /clients/:id controllers.Clients.show(id: Long)
1 つの URI パターンには、2 つ以上の動的パートを含められます
動的パートのデフォルトのマッチ規則は正規表現でいうと [^/]+
です。したがって、:id
という動的パートはちょうど一つの URI パートにマッチします。
§複数の /
をまたぐ動的パート
動的パートを使って、URI パスの /
で分割された複数のセグメントをまとめてキャプチャしたいときは、.*
という正規表現に対応する *id
という文法が使えます。
GET /files/*name controllers.Application.download(name)
これで、GET /files/images/logo.png
というリクエストに対して、動的パート name
に images/logo.png
という値をキャプチャさせることができます。
§独自の正規表現による動的パート
動的パートに独自の正規表現を使わせたい場合は、$id<regex>
という文法を利用します。
GET /clients/$id<[0-9]+> controllers.Clients.show(id: Long)
§アクションジェネレータメソッドの呼び出し
ルート定義の最後のパートは、アクションの呼び出しです。このパートでは、play.api.mvc.Action
の値を返すメソッドへの呼び出しを定義する必要があります。通常は、コントローラのアクションメソッドの呼び出しになります。
メソッドが一つも引数を取らない場合、単にメソッドの完全修飾名を指定します。
GET / controllers.Application.homePage()
アクションメソッドが引数を取る場合、全ての引数はリクエスト URI のパスまたはクエリストリングから抽出されます。
パスから抽出するためには、
# Extract the page parameter from the path.
GET /:page controllers.Application.show(page)
また、クエリストリングから抽出するためには、
# Extract the page parameter from the query string.
GET / controllers.Application.show(page)
のように定義します。
このルートに対応する controllers.Application
コントローラの show
メソッドの定義は次のようになります。
def show(page: String) = Action {
loadContentFromDatabase(page).map { htmlContent =>
Ok(htmlContent).as("text/html")
}.getOrElse(NotFound)
}
§引数の型
String
型の引数の場合、型の記述はオプションです。リクエストパラメータを特定の Scala 型に変換したいときは、型を明示することができます。
GET /client/:id controllers.Clients.show(id: Long)
このルートに対応する controllers.Clients
コントローラの show
メソッドの定義は次のようになります。
def show(id: Long) = Action {
Client.findById(id).map { client =>
Ok(views.html.Clients.display(client))
}.getOrElse(NotFound)
}
§引数に定数を渡す
アクションメソッドの引数に定数を渡したいときは、次のように記述します。
# Extract the page parameter from the path, or fix the value for /
GET / controllers.Application.show(page = "home")
GET /:page controllers.Application.show(page)
§デフォルト引数
受け取ったリクエストに値がないとき、代わりにデフォルト値を渡すこともできます。
# Pagination links, like /clients?page=3
GET /clients controllers.Clients.list(page: Int ?= 1)
§ルートの優先度
リクエストに複数のルートがマッチしてしまうことがあります。そのような競合が発生した場合は、先に宣言された方のルートが優先されます。
§リバースルーティング
Scala コード中で URL を生成するためにルータを使うこともできます。これにより、URI パターンの定義をただ一つの設定ファイルに集約することができ、アプリケーションをリファクタリングする際の間違いを減らすことができます。
ルータは、routes ファイルから利用された全てのコントローラについて、routes
パッケージ以下に リバースコントローラ
を生成します。リバースコントローラは元になったコントローラと同じシグネチャで、play.api.mvc.Result
の代わりに play.api.mvc.Call
を返すようなメソッドを持っています。
play.api.mvc.Call
は HTTP 呼び出しを表していて、HTTP メソッドと URL の両方の情報を持っています。
例えば、次のようなコントローラを作成したとします。
package controllers
import play.api._
import play.api.mvc._
object Application extends Controller {
def hello(name: String) = Action {
Ok("Hello " + name + "!")
}
}
そして、このコントローラを conf/routes
で次のようにマッピングしたとします。
# Hello action
GET /hello/:name controllers.Application.hello(name)
このとき、controllers.routes.Application
というリバースコントローラを利用することで、hello
というアクションメソッドの URL を逆引きすることができます。
// Redirect to /hello/Bob
def helloBob = Action {
Redirect(routes.Application.hello("Bob"))
}
次ページ: レスポンスの変更