§HTTP ルーティング
§ビルトイン HTTP ルータ
ルータとは、送られてきた HTTP リクエストをそれぞれ対応するアクションの呼び出しに変換する役割を持つコンポーネントです。
HTTP リクエストは MVC フレームワークにとってはイベントであるといえます。このイベントには、次の2つの重要データが含まれています。
- クエリストリングを含むリクエストパス (例えば、
clients/1542
、/photos/list
) - HTTP メソッド (例えば、 GET 、 POST 、 …)
ルートは conf/routes
ファイル内に定義され、コンパイルされます。したがって、ルート定義のエラーはブラウザ上ですぐ確認できます。
§ルートファイルの文法
conf/routes
はルータによって利用される設定ファイルです。このファイルにはアプリケーションの全てのルートの一覧があります。各ルートは HTTP メソッドと URI パターン、そしてその2つが関連付けられた Action
ジェネレータで構成されています。
ルート定義を例を見てみましょう。
GET /clients/:id controllers.Clients.show(id: Long)
各ルートの先頭は HTTP メソッドで、次が URI パターンです。最後の要素は呼び出し定義 (call definition) と呼ばれます。
#
から始まるコメント行を書くこともできます。
# 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()
§動的パート
例えば、クライアント ID を受け取るようなルートを定義する場合、次のような動的パートを使うことができます。
GET /clients/:id controllers.Clients.show(id: Long)
一つの URI パターンには、複数の動的パートを含められます
動的パートをマッチ方法は、デフォルトでは [^/]+
という正規表現になっています。したがって、 :id
のように定義した動的パートは、ちょうど一つの URI パートにマッチします。
§複数の / をまたぐ動的パート
/
から始まる複数の URI パスセグメントをキャプチャする動的パートを定義したい場合、 *id
という文法を使った動的パートが使えます。これには .*
という正規表現が使われます。
GET /files/*name controllers.Application.download(name)
GET /files/images/logo.png
のようなリクエストについて、 name
という動的パートは images/logo.png
という値をキャプチャします。
§動的パーツに使う正規表現のカスタマイズ
動的パートに独自の正規表現を使うためには、$id<regex>
という構文を使って次のような定義をします。
GET /items/$id<[0-9]+> controllers.Items.show(id: Long)
§アクションジェネレータメソッドの呼び出し
ルート定義の最後の部分は、アクションの呼び出しです。この部分には play.api.mvc.Action
型の値を返すようなメソッドの有効な呼び出しを書くことになっています。通常は、コントローラのアクションメソッドを呼び出すことになるでしょう。
メソッドに一つもパラメータが存在しない場合、単にメソッドの完全修飾名を書きます。
GET / controllers.Application.homePage()
アクションメソッドにパラメータが存在する場合は、全てのパラメータがリクエスト URI から検索され、 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
型のパラメータについては、型は指定しなくても構いません。しかし、送られてきたパラメータを Play に他の型へ変換させたい場合は、パラメータの型を明記する必要があります。
GET /clients/: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)
§省略可能なパラメータ
必ずしもリクエストに含まれていなくてもよい省略可能なパラメータを定義するためには、次のようにします。
# The version parameter is optional. E.g. /api/list-all?version=3.0
GET /api/list-all controllers.Api.list(version: Option[String])
§ルートの優先度
同じリクエストに複数のルートがマッチする可能性もあります。そのようなルートの競合が起こった場合、 (定義した順番が) 最初のルートが利用されます。
§リバースルーティング
ルータは Scala から呼び出して URL を生成させるという使い方もできます。これにより、全ての URI パターンを一つの設定ファイルに集約することができ、アプリケーションのリファクタリングをより安全に行うことができるようになります。
ルータはルートファイルで使われるそれぞれのコントローラについて routes
パッケージ以下に「リバースコントローラ」を生成します。リバースコントローラにはコントローラと同じシグネチャを持つ、同名のアクションメソッド定義されていますが、それぞれ play.api.mvc.Action
の代わりに play.api.mvc.Call
を返すようになっています。
play.api.mvc.Call
は HTTP 呼び出しを表していて、 HTTP メソッドと URI が両方とも含まれてます。
例えば、次のようなコントローラを作成した場合を考えてみます。
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
アクションメソッドの URI を逆引きすることができます。
// Redirect to /hello/Bob
def helloBob = Action {
Redirect(routes.Application.hello("Bob"))
}
次ページ: レスポンスの操作