Perl Hackers Hub

第70回 Raisin入門 ―Rest APIマイクロフレームワークを使ってみよう!(1)

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

本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーはWebサービスを開発している礒部浩行さんで,テーマは「Raisin入門」です。

本稿のコードは,執筆時点(2021年9月)の最新であるPerl 5.34.0とRaisin 0.93で動作確認を行っています。サンプルコードは,WEB+DB PRESS Vol.125のサポートサイトから入手できます。

Raisin ─⁠─Rest APIマイクロフレームワーク

Raisinは,Rest APIの実装に特化したマイクロフレームワークです。Perlにはさまざまなフレームワークが存在しますが,Rest APIの実装に特化したフレームワークは多くありません。

Raisinの登場背景

Raisinは,RubyのGrapeと,PerlのKelpというRestAPIフレームワークに触発されて開発されました。

Plack ─⁠─PSGIユーティリティ

RaisinはPlackをもとに作成されているため,まずPlackについて簡単に解説します。

Plackは,PSGIPerl Web Server Gateway Interfaceサーバを使ったWebアプリケーション開発のための周辺ライブラリ群です。plackupコマンドを使用することで,スタンドアローンアプリケーションとしてAPIを起動できます。

簡単な例として,次のファイルをhello.psgiという名前で保存して,plackupコマンドで起動します。

sub {
    return [
        '200',
        ['Content-Type' => 'text/plain'],
        ['Hello World']
    ];
}
$ plackup hello.psgi
HTTP::Server::PSGI: Accepting connections at
http://0:5000/

スタンドアローンアプリケーションとして起動しました。ブラウザでhttp://localhost:5000/を開くと,Hello Worldと表示されます。

PlackとPSGIについての詳しくは,本連載の第1回「PSGI/Plack ─⁠─フレームワークとサーバをつなぐエンジン」を参照してください。

PlackによるAPI開発の問題点

PlackをそのままAPI開発として使う場合,機能が少ないため,次のように長くて扱いづらいコードになります。

記述が冗長

Plackにはルーティング機能がありません。そのため,APIのエンドポイントを増やしたい場合は,if文などでリクエストパスを見て処理を分岐させるか,別途ルーティングモジュールが必要になります。

次のコードでは,ルーティングモジュールであるPlack::RequestRouter::Boomを使用しています。

use Plack::Request;
use Router::Boom;
use JSON qw/encode_json/;

my $router = Router::Boom->new();
$router->add('/users/all', sub {

    ['200',
    [
        'Content-Type' => 'application/json',
        'methods' => 'GET'
    ],
    [encode_json({
        'id' => 1,
        'name' => 'Sample Taro'
    })],
    ]
});

$router->add('/users/', sub {
    ['200',
    [
        'Content-Type' => 'application/json',
        'methods' => 'POST'
    ],
    [encode_json({
        'status' => 'success'
    })],
    ]
});

sub {
    my $env = shift;
    my ($destination, $captured) =
    $router->match($env->{PATH_INFO});

    my $req = Plack::Request->new($env);
    return $destination->($req);
}

これでは毎回レスポンスコードやContent-Typeを記述する必要があり,冗長です。

それに対してRaisinでは,レスポンスコードやContent-Typeを省略しても自動的に付与してくれます。

パラメータのチェック機能がない

Plackには入力値の型や必須パラメータのチェック機能がありません。そのため,if文などでチェックする必要があります。

次のコードでは,POSTのAPIでnameが付与されているかどうかのバリデーションを追加しています。

use JSON qw/encode_json decode_json/;

$router->add('/users/', sub {
    my $req = shift;
    my $json_data = decode_json($req->param);
    unless ($json_data->{ name }) {
        return ['400',
        [
            'Content-Type' => 'application/json',
            'methods' => 'POST'
        ],
        [encode_json({
            'status' => 'failed'
            'error_message' => "`name` is required",
            })],
        ]
    }
    ['200',
    [
        'Content-Type' => 'application/json',
        'methods' => 'POST'
    ],
    [encode_json({
        'status' => 'success'
    })],
    ]
});

今回はnameがあるかどうかをチェックしているだけですが,型の確認などを含めるとさらに複雑化します。エラー時のレスポンス内容も毎回記述する必要があり,1つのエンドポイントで正常系と異常系を毎回定義していくのは面倒です。

それに対してRaisinでは,バリデーションチェックを簡単に行えるメソッドがあり,エラー時のレスポンス内容も自動的に付与してくれます。

著者プロフィール

礒部浩行(いそべひろゆき)

フロント・バックエンドとWebメインに幅広く活動中。広告業界からオタク業界へ転職し,現在は通販サイトの開発を行っている。

大阪生まれ大阪育ちだが,東京に染まりすぎて最近関西弁が話せなくなった。

所属:虎の穴ラボ(株)
GitHub:mikenekoko