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

北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

PSGIを勉強したメモ(PlackとかMiddlewareとか)

Tatsumakiを触ってみたいなあと思ったらなんかPSGI/Plackの迷路に入ってしまい、つぶやいてたらid:miyagawaさんが色々教えて下さったので、せっかくなのでまとめておきます。

教えてもらってない自分で調べたことも書いてるので、間違ってたらごめんなさい!

PSGIとは

WEBアプリとWEBサーバ間の仕様です。仕様はここWSGIやRackのPerl版です。レガシーな分け方で言えば、CGI(or mod_perl or FastCGI)の仕様の層になります。

Plackとは

PSGIの仕様に関するリファレンス実装群です。

  • Plack(特にPlack::Server)
    • PSGIサーバのリファレンス実装。レガシーな分け方で言えば、これはApache等の層。
  • Plack::Request(と、Plack::Response)
    • PSGIアプリケーション用のユーティリティ。レガシーな分け方で言えば、これはCGI.pm等の層 *1

PlackPlack::Requestは、互いに依存しません(Plack-Request-0.05からそうなってます)。レガシーな例えをすれば、ApacheCGI.pmが依存してないのと同じです(どちらも、CGIの仕様に沿ってるだけ)。

なお、PSGIPlackの説明で気がつくと思いますが、これらは低レベルの層*2に位置しており、CatalystのようなWAFの層ではありません。WAFはこれらの上の層で構築されます。

てっとり早く試したい

1. Plackをインストール
2. app.psgiという名前のファイルを用意

use strict;
use warnings;

sub {
    my $env = shift;
    return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World" ] ];
};

3. app.psgiのあるディレクトリでplackup を実行
4. ブラウザで http://localhost:5000/ を開く

大事なのは、 app.psgiPSGIの仕様に沿って書かれたアプリなので、PlackじゃなくてもPSGIに対応したサーバさえあれば動くってことです*3

PSGI仕様におけるMiddlewareとは

PSGIアプリケーションに機能を付け加えて、新たなPSGIアプリケーションを作る物です。例えば、以下のような物。

package XHeader;
use strict;
use warnings;
use base Exporter::;
our @EXPORT = qw/xheader/;

# xheader is a middleware to wrap $app
sub xheader {
    my $app = shift;
    sub {
        my $env = shift;
        my $res = $app->($env);
        push @{$res->[1]}, 'X-PSGI-Used' => 1;
        return $res;
    };
}

これは例えば、以下のように適用します。

# app.psgi
use strict;
use warnings;
use XHeader;
 
# apply the middleware to a simple PSGI application
xheader sub {
    my $env = shift;
    return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World" ] ];
};

ただし、この適用法に関しては、(少なくとも現状では)PSGIの仕様の中では決められていません。Middlewareはクラスの形をとることもできますし、もっと別の形になっているかもしれません。

PlackにおけるMiddleware

Plackでは、Plack::Middlewareというベースクラスを提供しており、 Middleware の開発を容易にしてます。

Plack::Middleware に沿って Middleware を作ると、Plack::Builderの恩恵を受けて、DSL的にMiddlewareを適用することができます。

なお、現状ではPlack::Builderの提供するDSLは以下のようにサブルーチンの形のMiddlewareも適用できますが、ドキュメントにないのでなくなるかもとのことです。

# !!CAUTION!! サブルーチンへのenableはドキュメントにない。
#             そのうちサポートされなくなるかも。

# app.psgi
use strict;
use warnings;
use XHeader;
use Plack::Builder;

builder {
    enable \&xheader;
    sub {
        my $env = shift;
        return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World" ] ];
    };
};

><

*1:【2009-11-02 追記】他にCGI::PSGIと言うのもあり、こちらはCGI.pmと同じインタフェースを提供します。Plack::RequestはHTTP::Engine::RequestやCatalyst::Requestに近いインタフェースです。

*2:何も使わなければ、それこそ素のCGIで開発しているようなもんです(ある程度Middlewareは入ってますが)。Plack::Requestを使ってもCGI.pm的な時代にまでしかなりません。

*3:もうちょっと言えば、Plack::Request を使ってapp.psgiを使っても同じことが言えます。Plack::Server以外のPSGIに対応しているサーバで動かせます。