Plack::Middlewareの使い所

Songmu
2011-12-08

2011-12-08 00:40追記

@karupaneruraさんに指摘されて、s/Plack::Middleware::Conditionals/Plack::Builder::Conditionals/ しました。ありがとうございます。@kazeburoさんすみませんでした。


こんにちは。Songmuです。鎌倉の面白法人でPerlでソーシャルゲームの開発をおこなっています。 「ぼくらの甲子園熱闘編」や「ぼくらのワールドリーグ」の開発に携わっております。

アプリはArk + DBIx::Class + Text::MicroTemplate::Extendedという構成で作ることが多いのですが、 今回はソーシャルゲーム開発で活用しているPlack関連モジュールを2つ紹介させていただきます。

ちなみにArkのadvent calendarもやっておりますので、併せて読んでもらえると嬉しいです。

Plack::Middleware::Auth::OAuth

OAuthの署名チェックは少し面倒です。これをアプリケーション内でやろうとするのはいろいろな意味で筋悪です。

と言った理由からです。こういった処理は、PlackのMiddleware層でやるべき処理です。

すでにhidekさんが書かれた Plack::Middleware::Auth::OAuthがgithubに上がっているのでそれを使うと良いと思います。

psgiファイルをPlack::Builderを使って以下のように書くことができます。

use Plack::Builder;
...
builder {
    enable 'Plack::Middleware::Auth::OAuth',
        'consumer_key'    => 'your_consumer_key',
        'consumer_secret' => 'your_consumer_secret',
        'validate_post'   => 1;
    $app;
};

これで解決です。簡単ですね。これでアプリケーション側では特にOAuthを意識する必要はなくなりました。

ただ、これだと全てのアクセスにOAuth認証が必要になってしまい困る局面が出てきます。

例えば死活監視のためのURLを用意し、監視スクリプトに定期的にアクセスして貰う場合などです。

この場合監視スクリプト側がAuthヘッダーを付けてリクエストを送るのは現実的ではありません。 実装コストの問題や、たとえ実装ができたとしてもconsumer_key等の秘匿情報を監視スクリプト側に持たせたくないからです。

なので、enable_ifを使って、特定条件の場合にのみMiddlewareを読みこませるようしてみましょう。

builder {
    enable_if {$_[0]->{PATH_INFO} !~ m!^/ping(?:$|/)!}
        'Plack::Middleware::Auth::OAuth',
        'consumer_key'    => 'your_consumer_key',
        'consumer_secret' => 'your_consumer_secret',
        'validate_post'   => 1;
    $app;
};

上記の例だと、/ping 以下にアクセスした際にはOAuth認証を通さないようにしています。

/pingはDBのレコードを一行引き、問題なかったら200を返すようなURLです。それにより一気通貫のアプリケーションの死活監視を行うことができます。

Plack::Builder::Conditionals

さて、問題は解決しましたが、$_[0]->{PATH_INFO}みたいな生に近い情報を書くのは綺麗じゃないと思うかもしれません。

その場合は、kazeburoさん作のPlack::Builder::Conditionalsを使うと綺麗に書くことができます。

use Plack::Builder::Conditionals;

builder {
    enable match_if path('!', qr!^/ping(?:$|/)!),
        'Plack::Middleware::Auth::OAuth',
        'consumer_key'    => 'your_consumer_key',
        'consumer_secret' => 'your_consumer_secret',
        'validate_post'   => 1;
    $app;
};

コードの見通しが良くなりました。

まとめ

アプリケーションの処理を書いているときにアプリケーション側で頑張るのではなく、

で解決できないかを考えると、アプリケーションをシンプルにできることがあります。 特に、アプリケーションの本質とは関係ない処理をガリガリ実装してしまっている時に視点を広げてみると幸せになれることがあります。

また、便利だからといって、Plack::Middlewareをたくさん読み込ませると逆にpsgiファイルの見通しが悪くなってしまうことがあります。 そういう時は、Plack::Builder::Conditionalsを使うと良いでしょう。

さて、明日はhisaichi5518さんです。おや、会社の後輩ですね。お楽しみに。