なんでこんなものを書いてるんですか
最近はPSGI/Plackが普及してきてかなりWAFが書きやすくなってきたようですね!(僕がWAF触り始めたのは最近ですが。。。)
僕は最近はid:tokuhiromさんのAmon2がいい感じだなーと思って個人的に使っています。
ただ、社内で使うときに、社内での独自拡張が結構あったりとか、
プロジェクトごとの独自拡張が結構あったりとかして、
置き換えるのは結構骨が折れたりします。
例えば、Sledgeを使ったプロジェクトで以下のようなコードがあった場合、
Amon2で同じようなことをするためにはtriggerのあたりをどうするかで、結構骨が折れます。
比較的Sledge likeなid:nekokakさん作のKamuiを使うという手もありますが、
KamuiのControllerのメソッドのprefixはdo_となっていて、これは、
Kamui::Web::Handlerのdispatchメソッドにハードコードされているので、
これはオーバーライドしたりしない限り変えることはできないので、
これもやはり骨が折れます。
package Proj::Pages::Hoge; use strict; use warnings; __PACKAGE__->add_trigger(# Proj::Pages::Hoge以下のすべてのだけ有効にしたい 'BEFORE_DISPATCH' => sub { my $self = shift; # code }, ); sub dispatch_hoge { my $self = shift; # code } # ...
これら諸々の問題を解決するために、
・Sledgeから移行しやすいWAFがほしい!
って思ったりしたので僕が開発を始めたのがAtelierというWAFです。
っていうのは建前で、俺俺WAF作ってみたかったって思ったのが一番大きな理由だったりします。*1
Atelierってなんぞ?
拙作のSledge likeなインターフェースのPSGIの仕様に沿って作られているWeb Application Frameworkです。アトリエって読みます。
標準ではDispatcherとPages(Controller)しか提供しません。
Atelierは最小限の処理でアプリケーションを動かすために、最小限の機能しか備えていません。
それ以外の必要な機能はすべてPluginから利用するスタイルです。
ViewやTriggerすらもPluginで実装されています。
最小構成でのサンプルコードは以下のようになります。
# app.psgi use Atelier; Atelier->create_app( app => 'YourApp', # pass your app namespace ); # YourApp::Dispatcher package YourApp::Dispatcher; use Atelier::Dispatcher::RouterSimple; get '/' => +{ pages => 'Root', dispatch => 'index', }; 1; # YourApp::Pages package YourApp::Pages; use parent qw/Atelier::Pages/; 1; # YourApp::Pages::Root package YourApp::Pages::Root; use parent qw/YourApp::Pages/; sub dispatch_index { # "/" or "/index" path route to this dispatch. my $self = shift; return [ 200, [ 'Cotent-Type' => 'text/plain' ], [ 'Hello,world!' ], ]; } 1;
自由にHTTPレスポンスを作りたい極めて特殊なケースでは、上の例のようにPSGIのレスポンスを直接返す事で問題を解決出来ます。
またPages以下以外から直接例外的にレスポンスを返したい場合はAtelier::Plugin::Exception;のresponseというsuger関数で同様のことができます。(こちらは即時にレスポンスを返します。)
たとえばAtelier::Plugin::Renderer::JSONをPagesでuseして、
出力するデータを$self->stash、(もしくは__PACKAGE__->stash)に格納してあげればそれだけでデータをJSONにしてHTTPのレスポンスとして返すことができます。
Atelier::Plugin::Renderer::TiffanyをPagesでuseしてオプションを与え、
$self->templateに使用するテンプレートへのパスを与え、
出力するデータを$self->stash、(もしくは__PACKAGE__->stash)に格納してあげればそれだけでデータを任意のテンプレートエンジンで処理してHTTPのレスポンスとして返すことができます。
まだまだドキュメントを書けていないので詳しくはソースを読んでみてください。
なんでこんな低機能にしたの?
柔軟性をもたせるためです。
各プロジェクトをs/Slege/OtherWAF/gすることを考えたときに、
・Sledgeで使っていたプラグインはなるべくそのまま使いたい。
・動かなくなったら嫌なのであんまり書き換えたくない。
といった考えがありました。
なので、Sledgeと殆ど同じルールで書けるWAFが欲しかったのです。
なので、本当に最低限の機能だけ実装し、あとはPlugin等で
新たにメソッドをはやしたり、オーバーライドしたりすることで、
Sledgeに近づけていけるようにする。という事が出来るように意識して作りました。
なのでPagesは全体的にオーバーライドしやすくなっていると思います。
目的に応じてオーバーライドして使ってください。
Atelierについて
リポジトリはgithubで公開しています。
https://github.com/karupanerura/p5-Atelier
悪いところは山ほどあると思うので、ぜひ教えてください!
そしてもし良かったらpull reqください><
*1:ぶっちゃけ代替となりうるWAFは既に弊社内にあって実績もあったりするので