LoginSignup
17
14

More than 5 years have passed since last update.

Play2(Scala)のFilter機能で事前・事後処理を記述する

Posted at

Play2(Scala)のFilter機能で事前・事後処理を記述する

はじめに

BounscaleというオートスケールするHeroku Addonを作っています。

Bounscaleでは実験的にPlay2(Scala)への対応を実施中です。
オートスケールするにあたり、各種リソースの監視が必要なのですが、リソース値の取得をするためにPlay2のFilterの仕組みを利用しています。

Filterの使い方について下記にまとめます。

Filter?

FilterというとJavaのSevletFilterRuby on Railsのfilterなど、Webアプリケーション開発では比較的浸透した用語だと思います。

処理としてはある特定のURL/コントローラへのリクエストについて、共通的な事前/事後処理を提供する機構です。
J2EEパターン(懐)のIntercepting Filterが語源なのかな?

典型的には、認証処理などを統一的に記述して漏れなくアクセス制御を実現したりします。

バージョン

探した限りにはPlay1にはFilterの機構を見つけられませんでした。
Play2.1.1でFilterの機構が導入されたようなので、それ以降でしか動かないと思います。

流れ

基本的にはappディレクトリの下などにFilterクラスを作成し、Global#applyで登録するイメージです。

Filterの作成

appの下にこんな感じで書きます。

YourFilter.scala
package yourfilter

import play.api.mvc._
import play.api.libs.concurrent.Execution.Implicits._

class YourFilter extends Filter {
  def apply(next: (RequestHeader) => Result)(rh: RequestHeader) = {
    println("BEFORE")

    def after(result: PlainResult): Result = {
      println("AFTER")
      result
    }

    next(rh) match {
      case plain: PlainResult => after(plain)
      case async: AsyncResult => async.transform(after)
    }
  }
}

ポイントとしては、

  • Filterクラスを継承し、applyメソッドを実装する
  • next(req)の前が事前処理
  • 事後処理はメソッドとして定義しておく(非同期呼び出しに対応するため)
  • next(req)の戻り値の型がPlainResultなら同期的に、AsyncResultなら非同期的に事後処理メソッドを呼ぶ

Globalへの登録

下の感じで先ほどのFilterをGlobalに登録します。

Global.scala
import play.api.GlobalSettings
import play.api.mvc.WithFilters
import yourfilter.YourFilter

object Global extends WithFilters(
    new YourFilter) with GlobalSettings

実行

こんなサンプルアクションを定義して

Application.scala
package controllers

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

object Application extends Controller {

  def index = Action {
    println("action!")
    Ok(views.html.index("Your new application is ready."))
  }

}

このアドレスにアクセスしたら下記のログが出るようになりました。

BEFORE
action!
AFTER

所感

非同期処理を考慮する必要があるので記述がちょっと煩雑。もっとなんとかならないものかと思いました。

終わりに

このような事前・事後処理の多くはRubyではRack Middleware、node.jsではExpress Connect Middlewareの仕組みでも記述できます。

上記Middlwareの場合はフレームワークに到達する前に通過するので、より根っこの部分を抑えられます。
なので、例えばあるアクセスのCPU時間を取得するなどの場合は、そちらの方がフレームワークの処理時間も含めた正確な値が取れます。

Filterもいいのですが、PlayもMiddlewareの機構を提供してくれるとうれしい今日この頃です。

17
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
14