Play framework 2.0 betaが出たようです4 – ControllerとRouting

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コントローラーとHTTPルーティング

今回もGithubにあるwikiをベースにPlay framework2.0を動かしていきます。
ここにあるドキュメントはドラフトですが、ひととおりの機能を解説しています。
このドキュメントはJava版とScala版があり、それぞれの言語での使い方を説明しています。
いままでもそうでしたが、この記事ではScala版を見ながら解説していきます。
今回使用した動作環境は以下のとおりです。

  • OS : MacOS X 10.7.2
  • Playframework : 2.0β
  • Java : 1.6.0_26

注意:
この記事ではβ版を使用しています。
正式リリース前の状況のため思わぬ不具合が生じるかもしれませんので、ご了承ください。

ActionとController

Controllerについては、wikiのControllers and Actions ※1で説明しています。
ここの説明にそって解説を進めていきます。

まずはControllerについての説明です。
PlayframeworkにおいてControllerは、HTTPリクエストを受けてそれらを解析し、下位のモデルレイヤーに処理を渡します。
したがってこのレイヤーでは、リクエストやレスポンス(playのクラスにラップされてますが)を使用することが多いです。

基本的なController

プロジェクト作成時に雛形として提供されるControllerです。

package controllers

import play.api._
import play.api.mvc._

object Application extends Controller {
  
  def index = Action {
    Ok("It works!")
  }

}

playのControllerはシングルトンオブジェクトで、 play.api.mvc.Controller のサブクラスとして定義されます。
Scalaなので同一のファイル内に任意の数のControllerを記述できます。

Actionとは

Controllerの関数の戻り値であるAction は、Requestを引数にとり、Result(を実装したクラス)を返します。
下記のサンプルは、Ok(Results.Ok)を返しています。これはHTTPステータスの200をtext/plain形式で返します。

val echo = Action { request =>
  Ok("Got request [" + request + "]")
}

基本的なAction

ここでいくつかActionのパターンを確認してみます。
ControllerではHTTPリクエストが必要になることが多いですが、play.api.mvc.RequestをAction内で使用可能です。

def index = Action { request =>
  val name = request.queryString.get("name").flatMap(_.headOption)
  Ok("Hello " + name.getOrElse("Guest"))
}

Controllerに定義する関数はパラメータを持つことができますし、それをAction内で使用することも可能です。

def hello(name: String) = Action {
  Ok("Hello " + name)
}

Actionの構成

アクションの構成は簡単で、下記のようにすれば認証とキャッシュを適用したActionを使用できます。

def hello(name: String) = {
  Authenticated {
    Cached {
      Action {
        Ok("Hello " + name)
      }
    }      
  }
}

HTTPルーティング

HTTPルーティングについては、wikiのHttp Routing ※2で説明しています。
ここの説明にそって解説を進めていきます。

HTTPルーターは、conf/routesに定義してあるパスをチェックし、 リクエストされたURLに応じてControllerに定義してある関数を呼び出しを行います。
このconf/routesファイル内容はコンパイルされ、エラーの際には直接ブラウザでroutesのエラーが表示されます。

routesの書き方

confroutesファイルはルーターによって使用される構成ファイルです。
このファイルは、playアプリケーションに必要なすべてのルートを記述しています。
各ルートはHTTPメソッド、URIパターン、Actionを返すControllerの関数に紐付けられています。

GET         /                 controllers.Application.index
#これはコメント
POST        /user/:id         controllers.UserController.show(id:Long)

HTTP methodのパターン

HTTP methodについては、GET、POST、PUT、 DELETE、 HEADを記述することができます。

URIのパターン

URIパターンは、HTTPルートのリクエストパスを定義します。リクエストパスの部分は動的に定義することも可能です。

#これは静的なパス
GET   /clients/all              controllers.Clients.list()
#これは動的なパス
GET   /clients/:id          controllers.Clients.show(id: Long) 

例えば、IDによってクライアントを取得するルートを定義する場合、:idのようにして動的な部分を追加します。
デフォルトのURIマッチングパターンは正規表現で"[^/]+"となっています。
さらに、ワイルドカードを使用することもできますし、 $id<regex>のようにして正規表現を使用することもできます。

#/files/image/logo.png などがマッチする
GET   /files/*name          controllers.Application.download(name)  

#/clients/12345 などがマッチする
GET   /clients/$id<[0-9]+>  controllers.Clients.show(id: Long)  

ControllerのActionジェネレータ関数を呼ぶ場合

ルート定義の最後の部分はControllerの関数呼び出し部分です。
この関数は、play.api.mvc.Actionを返す関数でなくてはいけません。
Controllerの関数がパラメータなしの場合、完全修飾メソッド名を記述します。

GET   /clients          controllers.Clients.index()

controllerの関数はパラメータを取ることも可能です。
URIに埋め込む形式、クエリストリングを使用する形式が使用できます。

#localhost:9000/myidなどとアクセス
GET     /:id                         controllers.Application.show(id)
#localhost:9000/list?name=helloなどとアクセス
GET     /list                        controllers.Application.list(name)
def show(id:String) = Action {
    Ok(views.html.index("id=" + id))
}

def list(name:String) = Action {
    Ok(views.html.index("name=" + name))
}

パラメータは型を指定することも可能です。

GET     /:id                         controllers.Application.show(id:Long)
def show(id:Long) = Action {
    Ok(views.html.index("id=" + id))
}

さらに、URIに応じてパラメータを固定にすることも可能ですし、デフォルト値を設定することもできます。

#このURLの場合はid=1で固定
GET     /                     controllers.Application.show(id:Long = 1)
#デフォルト値を設定。localhost:9000/listでアクセスすると、nameは"hello"になる
GET     /list                        controllers.Application.list(name:String ?="hello")

リバースルーティング

Controllerに定義してある関数は、他のActionジェネレータ関数からも呼び出すことができます。
例えば下記のようなControllerとroutesがあるとします。

package controllers

import play.api._
import play.api.mvc._

object Application extends Controller {
    
  def hello(name: String) = Action {
      Ok("Hello " + name + "!")
  }
    
}
# Hello action
GET   /hello/:name          controllers.Application.hello(name)

他の関数(他のControllerでも可能)から呼び出すことにより、hello関数へURLを送ることができます。
リバースプロキシのような使いかたもできますので、複雑なルーティングの定義もよりシンプルに保つことができます。

// Redirect to /hello/Bob
def helloBob = Action {
    Redirect(controllers.routes.Application.hello("Bob"))    
}

まとめ

以上、Controller、Action、ルーティングの基本についてご紹介しました。
Play framewokr1.2(play-scala 0.9.1)から大きく変わった点は、Actionの概念ですね。
routesファイルの記述方法などは以前と変更はないようです。(おそらく。。。)
次回は新たに導入された機能、Application global settingsについての解説を予定しています。

参考サイトなど