§HTTPルーティング
§組み込みHTTPルーター
ルーターは、受信した各HTTPリクエストをアクションに変換する役割を担うコンポーネントです。
HTTPリクエストは、MVCフレームワークによってイベントとして認識されます。このイベントには、次の2つの主要な情報が含まれています。
- クエリ文字列を含むリクエストパス(例:
/clients/1542
、/photos/list
) - HTTPメソッド(例:
GET
、POST
など)。
ルートはコンパイルされるconf/routes
ファイルで定義されます。これは、ルートエラーがブラウザに直接表示されることを意味します。
§依存性注入
Playのデフォルトのルートジェネレーターは、@Inject
アノテーション付きのコンストラクターでコントローラーインスタンスを受け入れるルータークラスを作成します。つまり、このクラスは依存性注入での使用に適しており、コンストラクターを使用して手動でインスタンス化することもできます。
Play 2.7.0より前は、Playはコントローラーをclass
ではなくobject
として定義できる静的ルートジェネレーターをサポートしていました。Playはもはや静的状態に依存していないため、これはサポートされなくなりました。独自の静的状態を使用したい場合は、class
であるコントローラーで引き続き行うことができます。
§ルートファイルの構文
conf/routes
は、ルーターが使用する構成ファイルです。このファイルには、アプリケーションに必要なすべてのルートがリストされています。各ルートは、HTTPメソッドとURIパターンで構成され、両方ともAction
ジェネレーターの呼び出しに関連付けられています。
ルート定義がどのように見えるかを見てみましょう
GET /clients/:id controllers.Clients.show(id: Long)
各ルートは、HTTPメソッドで始まり、その後にURIパターンが続きます。最後の要素は、呼び出しの定義です。
#
文字を使用して、ルートファイルにコメントを追加することもできます。
# Display a client.
GET /clients/:id controllers.Clients.show(id: Long)
特定のプレフィックスの下で別のルーターを使用するようにルートファイルに指示するには、指定されたプレフィックスの後に“->”を使用します
-> /api api.MyRouter
これは、SIRDルーティングとしても知られる文字列補間ルーティングDSLと組み合わせたり、複数のルートファイルを使用してルーティングするサブプロジェクトを操作したりする場合に特に役立ちます。
また、ルートの先頭に+
で始まる行を付けることで、修飾子を適用することもできます。これにより、特定のPlayコンポーネントの動作を変更できます。このような修飾子の1つは、CSRFフィルターをバイパスする「nocsrf」修飾子です。
+ nocsrf
POST /api/new controllers.Api.newThing
§HTTPメソッド
HTTPメソッドは、HTTP(GET
、PATCH
、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
として定義された動的な部分は、正確に1つのURIパスセグメントと一致します。他のパターンタイプとは異なり、パスセグメントは、コントローラーに渡される前にルートで自動的にURIデコードされ、逆ルートでエンコードされます。
§複数の/
にまたがる動的な部分
動的な部分が、スラッシュで区切られた複数のURIパスセグメントをキャプチャする場合は、*id
構文(ワイルドカードパターンとも呼ばれます)を使用して動的な部分を定義できます。これは、.*
正規表現を使用します
GET /files/*name controllers.Application.download(name)
ここで、GET /files/images/logo.png
のようなリクエストの場合、name
動的部分はimages/logo.png
の値をキャプチャします。
複数の/
にまたがる動的な部分は、ルーターによってデコードされず、逆ルーターによってエンコードされないことに注意してください。ユーザー入力の場合と同じように、生のURIセグメントを検証するのはあなたの責任です。逆ルーターは単に文字列連結を行うだけなので、結果のパスが有効であり、たとえば複数の先頭のスラッシュや非ASCII文字が含まれていないことを確認する必要があります。
§カスタム正規表現を使用した動的な部分
$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が受信したパラメーターを特定のScala型に変換する場合は、パラメーターを明示的に型指定できます
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)
}
Playは、次のパラメーター型をサポートしています
- 文字列
- Int
- 長整数
- 倍精度浮動小数点数
- 浮動小数点数
- ブール値
- UUID
- サポートされている他の型のAnyValラッパー
別の型があり、それを実装する場合は、リクエストバインダーを参照してください
§固定値を持つパラメーター
パラメーターに固定値を使用したい場合があります
# 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])
§リストパラメーター
繰り返されるクエリ文字列パラメーターにリストパラメーターを指定することもできます
# The item parameter is a list.
# E.g. /api/list-items?item=red&item=new&item=slippers
GET /api/list-items controllers.Api.listItems(item: List[String])
# or
# E.g. /api/list-int-items?item=1&item=42
GET /api/list-int-items controllers.Api.listIntItems(item: List[Int])
§ルーティング優先度
多くのルートが同じリクエストに一致する可能性があります。競合がある場合は、最初のルート(宣言順)が使用されます。
§逆ルーティング
ルーターは、Scala呼び出し内からURLを生成するためにも使用できます。これにより、すべてのURIパターンを単一の構成ファイルに集中させることができるため、アプリケーションをリファクタリングするときに自信を持つことができます。
ルートファイルで使用されるコントローラーごとに、ルーターはroutes
パッケージに「逆コントローラー」を生成します。このコントローラーは、同じアクションメソッドを持ち、署名は同じですが、play.api.mvc.Action
ではなくplay.api.mvc.Call
を返します。
play.api.mvc.Call
はHTTP呼び出しを定義し、HTTPメソッドとURIの両方を提供します。
たとえば、次のようなコントローラーを作成した場合
package controllers
import javax.inject.Inject
import play.api._
import play.api.mvc._
class Application @Inject() (cc: ControllerComponents) extends AbstractController(cc) {
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"))
}
注: 各コントローラーパッケージには
routes
サブパッケージが存在します。したがって、アクションcontrollers.Application.hello
は、controllers.routes.Application.hello
を介してリバースできます(routes ファイル内で、生成されたパスに一致する別のルートがその前にない場合に限ります)。
リバースアクションメソッドは非常に単純に機能します。パラメータを受け取り、それらをルートパターンに代入します。パスセグメント(:foo
)の場合、値は代入が行われる前にエンコードされます。正規表現およびワイルドカードパターンについては、値が複数のセグメントにまたがる可能性があるため、文字列は生の形式で代入されます。リバースルートに渡す際に、これらのコンポーネントを必要に応じてエスケープし、検証されていないユーザー入力を渡さないようにしてください。
§相対ルート
絶対ルートではなく相対ルートを返すことが有用な場合があります。play.mvc.Call
によって返されるルートは常に絶対ルート(/
で始まる)であり、WebアプリケーションへのリクエストがHTTPプロキシ、ロードバランサー、およびAPIゲートウェイによって書き換えられる場合に問題を引き起こす可能性があります。相対ルートの使用が有用な例を以下に示します。
conf/routes
ファイルで設定されているものとは異なるプレフィックスをすべてのルートに付けるWebゲートウェイの背後でアプリをホストし、アプリケーションを予期していないルートでルート化する場合。- スタイルシートを動的にレンダリングする場合、CDNによって異なるURLから提供される可能性があるため、アセットリンクを相対にする必要があります。
相対ルートを生成できるようにするには、ターゲットルートを相対化する基準(開始ルート)を知る必要があります。開始ルートは現在の RequestHeader
から取得できます。したがって、相対ルートを生成するには、現在の RequestHeader
または開始ルートを String
パラメータとして渡す必要があります。
例えば、次のようなコントローラーエンドポイントがある場合
package controllers
import javax.inject._
import play.api.mvc._
@Singleton
class Relative @Inject() (cc: ControllerComponents) extends AbstractController(cc) {
def helloview: Action[AnyContent] = Action { implicit request => Ok(views.html.hello("Bob")) }
def hello(name: String): Action[AnyContent] = Action {
Ok(s"Hello $name!")
}
}
注: 現在のリクエストは、
implicit request
を宣言することで、ビューテンプレートに暗黙的に渡されます。
conf/routes
ファイルにそれをマップした場合
GET /foo/bar/hello controllers.Relative.helloview
GET /hello/:name controllers.Relative.hello(name)
これまでと同様にリバースルーターを使用して相対ルートを定義し、relative
への追加呼び出しを含めることができます。
@(name: String)(implicit request: RequestHeader)
<h1>Hello @name</h1>
<a href="@routes.Relative.hello(name)">Absolute Link</a>
<a href="@routes.Relative.hello(name).relative">Relative Link</a>
注: コントローラーから渡された
Request
はRequestHeader
にキャストされ、ビューパラメータでimplicit
とマークされます。その後、relative
への呼び出しに暗黙的に渡されます。
/foo/bar/hello
をリクエストすると、生成されるHTMLは次のようになります。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bob</title>
</head>
<body>
<a href="/hello/Bob">Absolute Link</a>
<a href="../../hello/Bob">Relative Link</a>
</body>
</html>
§デフォルトコントローラー
Playには、便利なアクションをいくつか提供する Default
コントローラーが含まれています。これらはroutesファイルから直接呼び出すことができます。
# Redirects to https://play.dokyumento.jp/ with 303 See Other
GET /about controllers.Default.redirect(to = "https://play.dokyumento.jp/")
# Responds with 404 Not Found
GET /orders controllers.Default.notFound
# Responds with 500 Internal Server Error
GET /clients controllers.Default.error
# Responds with 501 Not Implemented
GET /posts controllers.Default.todo
この例では、GET /about
は外部Webサイトにリダイレクトしますが、別のアクション(上記の例では /posts
など)にリダイレクトすることも可能です。
§カスタムルーティング
Playには、_String Interpolating Routing DSL_、略してSIRDと呼ばれる組み込みルーターを定義するためのDSLが用意されています。このDSLには、軽量のPlayサーバーの埋め込み、通常のPlayアプリケーションへのカスタムまたはより高度なルーティング機能の提供、テスト用のRESTサービスのモックなど、多くの用途があります。
String Interpolating Routing DSL を参照してください。
次へ: HTTP結果の操作
このドキュメントに誤りを見つけましたか?このページのソースコードは こちら にあります。 ドキュメントのガイドライン を読んだ後、プルリクエストを自由に貢献してください。質問や共有するアドバイスがありますか? コミュニティフォーラム にアクセスして、コミュニティとの会話を始めましょう。