Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

PrePANをAmon2化した + Amon2で気になった点など

PrePANのWebアプリケーションフレームワークAmon2に変更しました。閲覧者的には何も変わるところはないので特に意味はないですが、今後の機能開発がしやすくなったので、結果的にはよい影響はあると期待しているところです。

WAFは、YAPC::Asia 2011でのcho45さんの発表「ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく」にあるように「薄いフレームワーク」がより良いと最近は感じています。PrePANはまあ、特に変わったこともしていないアプリなので、ドメインスペシフィックに対処するべきこともなく、また、下手に自作するよりも、Amon2の方がずっといいものであることが明白なので、今回はAmon2を使うことにしました。

というわけで、Amon2作者のtokuhiromさんに「Amon2使いますよ!!1」と話したのを実行できたし、PrePANはいろいろと機能追加の構想があって、継続的に取り組んでいこうと思っているのですが、その足がかりをちゃんと築けたので、よかったです。

Amon2使ってて気になったところ

エラーハンドリング

Amon2::Webにres_404()ってのが実装されてるけど、他のやつは自分で書かなければならない(?)。いまはとりあえず必要な分だけべたっと書いた。

シリアライザー

APIがJSONなどで返す時に、適当にデータ構造をわたしたらシリアライズする仕組みがあるといいかもしれないけど、まあ自分で書いてもそんな手間でもないのでres_jsonみたいなメソッド書いた。

追記: Amon2::Plugin::Web::JSONってのが標準で入ってた!

BasicフレイバーでCSRF防止プラグインが有効になっている件

Basicフレイバーでは、Amon2::Plugin::Web::CSRFDefenderが有効化されているのだけど、これはHTMLに自動的にCSRF防止用のトークンを埋め込んでくれるのだけど、JavaScriptでPOSTするような場合は自分で$c->get_csrf_defender_tokenを使ってtokenを取得、リクエストに埋め込む必要がある。

そのメソッドを使うと便利とドキュメントにはあるのだけど、そもそもCSRF防止プラグインがフレイバー内で有効になっているのを見逃していたら、JavaScriptからPOSTした時だけ403が返ってくる理由がわかんなくて、ハマりそう。

config

この件、下記追記を参照のこと

環境変数によってWAFがいい感じに設定をロードしてくれるみたいな仕組みは便利なんだけど、ついついモデルの設定などの、Webに直接関係のない設定も全部書いてしまいがちだと思う。そうすると、モデルを利用するだけなのにWAFに依存することになって、非常によろしくない。それで最近は、設定のコンテナはWAFから切り離してConfig::ENVを使うようにしている。

Amon2にも設定を上記のようにロードする仕組みはあるけど、Amon2#configがHashRefを返せばいいという軽い制約を課すだけなので、気に入らなければ簡単に上書きして差し替えることができる。ただし、Config::ENVとの相性があまりよくないので、ハック的だけど、以下のようにして対応した。これで、$c->configが見かけ上HashRefを返すようになったので、Amon2の仕様とConfig::ENVの仕様とをつなぐことができた。

Amon2 + Config::ENVを推すなら、Amon2::Config::Envみたいなモジュールを作るか、あるいは、Config::ENVが以下のようなtieされたHashRefを返すかした方がいい感じがするのだけど、どっちがいいのかちょっと判断がつかないところ。

{
    package PrePAN::Config::Adaptor;
    use Tie::Hash;
    sub TIEHASH {
        my ($class, %args) = @_;
        bless \%args, $class;
    }

    sub FETCH {
        my ($self, $key) = @_;
        PrePAN::Config->param($key);
    }

    for my $method(qw(STORE FIRSTKEY NEXTKEY EXISTS DELETE CLEAR SCALAR)) {
        no strict 'refs';
        *{__PACKAGE__ . "\::$method"} = sub {};
    }
}

tie my %config, 'PrePAN::Config::Adaptor';

sub load_config { \%config }
sub config      { \%config }
configに関する追記

上記のようなことをいっていたらcho45さんが、Config::ENVに現在の設定をまるごとhashで返すcurrent()メソッドを追加してくれました(0.09)。なので、上記のようにtieしたりすることなく、

sub config { PrePAN::Config->current }

こんな感じで書くだけでよくなりました。やったー。