読者です 読者をやめる 読者になる 読者になる

play2でフィルター処理を実現する

前回の記事 をベースに考えて、なんとなく動くフィルター処理を作ってみました。

https://github.com/rabitarochan/play2-filter-sandbox

フィルターの書き方についてはだいたいイメージ通りに行きました。

object Application extends Controller with FilterController {
  
  def index = LoggingFilter >> WithAction { req =>
    Ok(views.html.index("Your new application is ready."))
  }
  
  case class User(name: String, password: String)
  
  case object UserKey extends AttributeKey[User]

  /**
   * 認証もどきのフィルター。
   * 
   * QueryString に user と password が設定されていて、
   * その値が同じであれば User を作成して次の処理へ進む。
   * それ以外の場合は認証エラー (Unauthorized) を返す。 
   */
  def AuthFilter = Filter { req: AttributedRequest[AnyContent] =>
    val userOpt = req.getQueryString("user")
    val passwordOpt = req.getQueryString("password")
    
    (userOpt, passwordOpt) match {
      case (Some(user), Some(password)) if user == password => {
        continueWith(UserKey -> User(user, password))
      }
      case _ => Unauthorized("user is not equal password.")
    }
  }
  
  /**
   * ログを出力するだけのフィルター
   */
  def LoggingFilter = Filter { req: AttributedRequest[AnyContent] =>
    Logger.debug(s"[${req.method}] ${req.path}")
    continue
  }
  
  
  def test = 
    LoggingFilter >>
    AuthFilter >>
    WithAction { implicit request =>
      val user = UserKey.get
      Ok(s"Action: ${user}")
    }
  
}

次のフィルター、アクションにパラメータを渡すあたりの実装は、t2v/stackable-controllerをかなり参考にさせていただきました。

なぜこれを作ったのか

参考にさせていただいた stackable-controller は、StackableControllerを継承したトレイトをControllerにmixinしていくことで、同じように共通処理を実行できます。

ただ、このフィルターのように、実際どのような処理が行われているのかが見えるほうが分かりやすいのではないかと思い、作ってみることにしました。

ふと思いついた、という理由が大きかったり。

課題

テスト等もまだまだ不十分ですし、これを使って何かを作ったわけではないです。それはこれからとして、今の時点でどうにかならないか考えていることが何個かあります。

1. Filterのリクエストの型を明示しない方法を作りたい

上記のコードの通り、全てのFilter処理のリクエストに型を明示しています。これを書かないとコンパイルが通らないため書いていますが、どうにか明示しない方法がないかを模索しています。

完全に書かないわけにはいかないと思うので、フィルターの型パラメータにするなどで、省略出来ればいいかなーと考えています。

// Filterの型パラメータとして
def HogeFilter = Filter[java.io.File] { req => 
  continue
}

// 省略したら AnyContent とみなす

def HogeFilter = Filter { req =>
  continue
}

2. 内部処理はなるべくPlay2標準のActionを利用するようにしたい

現在はFilter処理を保持するためにFilterActionというクラスを作っていますが、独自のものよりは標準で用意されているものを使ったほうがいいのかなと思っています。

3. 英語・・・

scaladocを英語で書きたかったのですが、読めるけど書けないというなんとも残念な感じなので、どうにかしたいところです。


とりあえず動くところまでは行ったので、あとは使いながら修正していこうかなと思います。もう少ししっかり作れば、最低限のフィルター処理的なものに使えると思うので、実用出来るところまで持って行きたいです。