Perl Hackers Hub

第41回 Plack::Middleware再入門(3)

この記事を読むのに必要な時間:およそ 3.5 分

prepare_app─⁠─ロード後に一度だけ呼ばれるメソッド

Plack::Middlewareにはprepare_appというメソッドを書くことができ,ロード後に1度だけ呼ばれます。重いインスタンス生成をcallメソッドの外に追い出したり,ミドルウェアのオプションの初期値を設定したりする場面で使います。

次のコードではprepare_appでData::UUIDのインスタンス生成を行いつつ,callbackにデフォルトのコードリファレンスを設定しています。

package Plack::Middleware::Foo;
use parent qw( Plack::Middleware );
use Plack::Util::Accessor qw( uuid callback );
use Data::UUID;

sub prepare_app {
    my $self = shift;

    $self->uuid(Data::UUID->new);

    unless ($self->callback) {
        $self->callback(sub {
            my $res = shift;
            warn "status:$res->[0]\n";
        });
    }
}

sub call {
    my ($self, $env) = @_;

    $env->{psgix.uuid} = $self->uuid->create_str();

    my $res = $self->app->($env);

    $self->callback->($res);

    return $res;
}

Plack::Middlewareのテスト

最後はテストについて紹介します。

Plack::Middlewareは,基本的にPSGIアプリケーションと同じように$envを受け取ってレスポンスを返すという挙動をするものなので,テストも同様に書けます。つまり,Plack::TestやTest::WWW::Mechanize::PSGIといったモジュールを利用して書くことができます。アプリケーションとクライアントのシンプルなやりとりをテストするならPlack::Testが最適です。フォーム送信をはじめとしたコンテンツ周りのより複雑な挙動をテストするならTest::WWW::Mechanize::PSGIが便利です。

Plack::Testを使ったテスト

use Plack::Builder;
use HTTP::Request::Common;
use Test::More;
use Plack::Test;

my $app = builder {
    enable 'ETag';
    sub {[
        200,
        ['Content-Type' => 'text/plain'],
        ['OK']
    ]};
};

my $cli = sub {
    my $cb = shift;
    my $res = $cb->(GET '/');
    is $res->code, 200;
    is $res->content_type, 'text/plain';
    is $res->content, 'OK';
    is $res->header('ETag'),
            '9ce3bd4224c8c1780db56b4125ecf3f24bf748b7';
};

test_psgi $app, $cli;

done_testing;

Test::WWW::Mechanize::PSGIを使ったテスト

use Test::WWW::Mechanize::PSGI;
use Test::More;
use Plack::Builder;

my $mech = Test::WWW::Mechanize::PSGI->new(
    app => builder {
        enable 'ETag';
        sub {[
            200,
            ['Content-Type' => 'text/plain'],
            ['OK']
        ]};
    },
);

$mech->get_ok('/');
is $mech->ct, 'text/plain';
$mech->content_is('OK');
$mech->header_is(
    'ETag', '9ce3bd4224c8c1780db56b4125ecf3f24bf748b7'
);

done_testing;

Plack::Middlewareのテストは比較的パターンが決まっているので,CPANにある多種多様なPlack::Middlewareの中から,似通ったものを探してそれを参考に書くのが一番簡単かもしれません。

また,筆者がPlack::Middlewareを書くときによくやるのは,先述したPlack::Middleware::DebugLoggingを有効にして,テスト中もリクエストとレスポンスの中身を見えるようにしておくことです。これにより,テストで利用するモジュール群が内部的にリクエストやレスポンスをよしなに扱ってくれる部分も,その都度見ることができます。何か困ったことが発生してからテストコードでprintデバッグするよりもずっと効率的です。

まとめ

Plack::MiddlewareはWebサーバとアプリケーションをつなぐ層でさまざまな仕事をします。今回はそのしくみを理解するところからはじめ,代表的なモジュールの紹介,そしてPlack::Middlewareを書くときに必須のユーティリティからテストまで,できる限り具体的に解説してみました。これを機に,みなさんのプロジェクトに眠るミドルウェアがCPANizeされたり,新しく有用なミドルウェアが登場してきたりすると非常にうれしく思います。

さて,次回の執筆者は星野将さんで,テーマは「広告配信サーバの事例から見るPerlとCPANモジュールの活用」です。

WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.111

2019年6月24日発売
B5判/160ページ
定価(本体1,480円+税)
ISBN978-4-297-10657-7

  • 特集1
    新機能の数々をコミッターが最速解説!
    詳解Rails 6
    新コンポーネント,複数DB対応,並列テスト,オートロード刷新
  • 特集2
    動的かつ高速!
    はじめてのJulia
    科学技術計算のための新言語
  • 特集3
    見える化大作戦
    進捗,成果,無理/ムダ,個人の気持ち……
  • 一般記事
    Elm入門
    型安全な関数型言語によるフロントエンド開発

著者プロフィール

岡林大(おかばやしだい)

主にPerlでサーバサイドを書く人ですが,たまにJavaScriptでフロントも書きます。自由でロックなWebが大好き。お仕事以外ではラーメンを食べるかOSSに貢献する#yapcramenの人。

GitHub:bayashi