§文字列補間ルーティングDSL
Playは、文字列補間ルーティングDSL(略してsird)と呼ばれる、埋め込みルーターを定義するためのDSLを提供します。このDSLは、軽量なPlayサーバーの埋め込み、通常のPlayアプリケーションへのカスタムまたはより高度なルーティング機能の提供、テストのためのRESTサービスのモックなど、多くの用途があります。
Sirdは、文字列補間抽出オブジェクトに基づいています。Scalaが文字列(および任意のオブジェクト)の構築のためにパラメーターを文字列に補間することをサポートするのと同じように(例:`s"Hello $to"`)、同じメカニズムを使用して、たとえばcase文で文字列からパラメーターを抽出することもできます。
このDSLは、play.api.routing.sird
パッケージにあります。通常、このパッケージと他のいくつかのパッケージをインポートすることをお勧めします。
import play.api.mvc._
import play.api.routing._
import play.api.routing.sird._
使用方法の簡単な例を以下に示します。
val router = Router.from {
case GET(p"/hello/$to") =>
Action {
Results.Ok(s"Hello $to")
}
}
この場合、補間されたパスパターン内の$to
パラメーターは、アクションで使用するための単一のパターンのセグメントを抽出します。GET
抽出器は、GET
メソッドを持つリクエストを抽出します。RequestHeader
を受け取り、同じRequestHeader
パラメーターを抽出します。これは便利なフィルターとしてのみ使用されます。POST
、PUT
、DELETE
を含む他のメソッド抽出器もサポートされています。
Playのコンパイル済みルーターと同様に、sirdは複数のパターンのセグメントパラメーターのマッチングをサポートしており、これはパラメーターに*
を付加することで行われます。
val router = Router.from {
case GET(p"/assets/$file*") =>
Assets.versioned(path = "/public", file = file)
}
正規表現もサポートされており、パラメーターに山括弧で囲まれた正規表現を付加することで行われます。
val router = Router.from {
case GET(p"/items/$id<[0-9]+>") =>
Action {
Results.Ok(s"Item $id")
}
}
クエリパラメーターも抽出でき、?
演算子を使用してリクエストでさらに抽出を行い、q
抽出器を使用します。
val router = Router.from {
case GET(p"/search" ? q"query=$query") =>
Action {
Results.Ok(s"Searching for $query")
}
}
q
が必須クエリパラメーターをString
として抽出する一方で、Scala 2.10を使用する場合はq_?
またはq_o
がオプションのクエリパラメーターをOption[String]
として抽出します。
val router = Router.from {
case GET(p"/items" ? q_o"page=$page") =>
Action {
val thisPage = page.getOrElse("1")
Results.Ok(s"Showing page $thisPage")
}
}
同様に、q_*
またはq_s
を使用して、複数値のクエリパラメーターのシーケンスを抽出できます。
val router = Router.from {
case GET(p"/items" ? q_s"tag=$tags") =>
Action {
val allTags = tags.mkString(", ")
Results.Ok(s"Showing items tagged: $allTags")
}
}
複数のクエリパラメーターは、&
演算子を使用して抽出できます。
val router = Router.from {
case GET(
p"/items" ? q_o"page=$page"
& q_o"per_page=$perPage"
) =>
Action {
val thisPage = page.getOrElse("1")
val pageLength = perPage.getOrElse("10")
Results.Ok(s"Showing page $thisPage of length $pageLength")
}
}
sirdは単なる通常の抽出オブジェクト(文字列補間によって構築される)であるため、他の抽出オブジェクトと組み合わせることができ、さらにサブパラメーターを抽出することもできます。Sirdは、最も一般的なタイプの一部について、すぐに使用できるいくつかの便利な抽出器を提供しており、具体的にはint
、long
、float
、double
、bool
があります。
val router = Router.from {
case GET(p"/items/${int(id)}") =>
Action {
Results.Ok(s"Item $id")
}
}
上記のid
はInt
型です。int
抽出器が一致しなかった場合、もちろん、パターン全体が一致しなくなります。
同様に、同じ抽出器をクエリ文字列パラメーターで使用でき、複数値およびオプションのクエリパラメーターも含まれます。オプションまたは複数値のクエリパラメーターの場合、存在する値のいずれかが型にバインドできないと一致は失敗しますが、パラメーターが存在しない場合は一致が失敗することはありません。
val router = Router.from {
case GET(p"/items" ? q_o"page=${int(page)}") =>
Action {
val thePage = page.getOrElse(1)
Results.Ok(s"Items page $thePage")
}
}
これらが単なる通常の抽出オブジェクトであることをさらに説明するために、ここでは、@
構文やif文など、case
文の他のすべての機能を使用できることを示しています。
val router = Router.from {
case rh @ GET(
p"/items/${idString @ int(id)}" ?
q"price=${int(price)}"
) if price > 200 =>
Action {
Results.Ok(s"Expensive item $id")
}
}
§Sird Routerのバインディング
アプリケーションでsird Routerを使用するように構成する方法は、ユースケースに応じて複数あります。
§routesファイルからのSIRDルーターの使用
routesファイルとコントローラーを使用する通常のPlayプロジェクトと組み合わせてルーティングDSLを使用するには、SimpleRouter
を拡張します。
package api
import javax.inject.Inject
import play.api.mvc._
import play.api.routing.sird._
import play.api.routing.Router.Routes
import play.api.routing.SimpleRouter
class ApiRouter @Inject() (controller: ApiController) extends SimpleRouter {
override def routes: Routes = {
case GET(p"/") => controller.index
}
}
次の行をconf/routesに追加します。
-> /api api.ApiRouter
§SIRDルーターの合成
Routesは部分関数であるため、複数のルーターを合成できます。したがって、ルートをより小さく、より焦点を絞ったルーターに分割し、後でアプリケーションルーターで合成できます。たとえば、上記のApiRouter
と、次のような新しいSinglePageApplicationRouter
を検討してみましょう。
class SpaRouter @Inject() (controller: SinglePageApplicationController) extends SimpleRouter {
override def routes: Routes = {
case GET(p"/api") => controller.api
}
}
次に、両方を合成して、アプリケーション全体のルーターを作成できます。
class AppRouter @Inject() (spaRouter: SpaRouter, apiRouter: ApiRouter) extends SimpleRouter {
// Composes both routers with spaRouter having precedence.
override def routes: Routes = spaRouter.routes.orElse(apiRouter.routes)
}
§Playの埋め込み
sirdルーターを使用してPlayサーバーを埋め込む例は、Playの埋め込みセクションにあります。
§DIルーターの提供
ルーターは、アプリケーションエントリポイントとルーターの提供で説明されているように、アプリケーションに提供できます。
class SirdAppLoader extends ApplicationLoader {
def load(context: Context) = {
new SirdComponents(context).application
}
}
class SirdComponents(context: Context) extends BuiltInComponentsFromContext(context) with NoHttpFiltersComponents {
lazy val router = Router.from {
case GET(p"/hello/$to") =>
Action {
Ok(s"Hello $to")
}
}
}
§Guiceを使用したDIルーターの提供
GuiceベースのPlayアプリでは、GuiceApplicationLoader
とProvider[Router]
をオーバーライドすることで、SIRDルーターを提供できます。
class ScalaSimpleRouter @Inject() (val Action: DefaultActionBuilder) extends SimpleRouter {
override def routes: Routes = {
case GET(p"/") =>
Action {
Results.Ok
}
}
}
@Singleton
class ScalaRoutesProvider @Inject() (playSimpleRouter: ScalaSimpleRouter, httpConfig: HttpConfiguration)
extends Provider[Router] {
lazy val get = playSimpleRouter.withPrefix(httpConfig.context)
}
class ScalaGuiceAppLoader extends GuiceApplicationLoader {
protected override def overrides(context: ApplicationLoader.Context): Seq[GuiceableModule] = {
super.overrides(context) :+ (bind[Router].toProvider[ScalaRoutesProvider]: GuiceableModule)
}
}
SIRDルーターはroutesファイルよりも強力で、IDEからよりアクセスしやすくなっています。
§バインディングのオーバーライド
ルーターは、バインディングとモジュールで説明されているように、アプリケーションローダーでたとえばGuiceApplicationBuilderを使用して、カスタムルーターバインディングまたはモジュールでオーバーライドすることもできます。
このドキュメントに誤りを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインを読んだ後、プルリクエストを送信してください。質問やアドバイスがありましたら、コミュニティフォーラムにアクセスして、コミュニティとの会話を開始してください。