はじめに
perlを使った開発に本格的に取り組むことになりそうだったので理解するためにまずはWebアプリケーションを作ってみる。
今回のゴールとしてはリクエストを受けてレスポンスを正常に返すところまでとする。
Dockerfileの用意
FROM perl:5.18
WORKDIR /srv/sources
RUN cpanm Server::Starter
RUN cpanm HTTP::Router
RUN cpanm Plack
RUN cpanm Gazelle
本当はcartonを使ってモジュール管理をするのがいいみたいだけども今回はとりあえず一つずつ必要なモジュールをインストールする。
一つのRUNにまとめても良かったが必要になったタイミングでコマンド追加という風にやっていたせいで、都度ビルドを行うと全てのインストールが再度行われて時間がかかりすぎるため、コマンドを分割することにした。
以下、使用するモジュールの用途について。
Server::Starter
プロセスのHot deployに対応するためのモジュール。
詳しい内容についてはこちらの記事で紹介されている。
HTTP::Router
ルーティングを行うためのモジュール。
Plack
PSGIサーバモジュール。
PSGIについてはこちらの記事を読むといいかもしれない。
これでリクエストの処理やレスポンスの構築などを行う。
Gazelle
高速なアプリケーションサーバモジュール。
Gazelleについてはこちらの記事で紹介されているのでこちらを参照するといい。
docker-compose
version: '3'
services:
app:
build: ./docker
ports:
- 8080:80
volumes:
- ./:/srv/sources
command: ["start_server", "--port", "80", "--", "plackup", "-I", "src/", "-s", "Gazelle", "-E", "development", "app.psgi"]
アプリケーションのdockerへのマウントはdocker-compose側で行う。(その方が楽だったので)
app.psgi
use strict;
use warnings;
use utf8;
use Plack::Request;
use Plack::Response;
use Data::Dumper;
use HTTP::Router::Declare;
use API;
my $router = router {
match '/', { method => 'GET' }, to { app => \&API::top }
};
sub dispatch {
my ($req) = @_;
my $match = $router->match($req) or return $req->new_response(404)->finalize;
return $match->params->{ app }($req, $match)->finalize;
}
my $app = sub {
my $req = Plack::Request->new(shift);
my $r = eval { dispatch($req) };
my $errstr = $@ or return $r;
warn $errstr;
my $res = $req->new_response(503);
$res->content_type('text/html');
$res->body('Error');
return $res->finalize;
};
エントリーポイントのファイル。
実処理を書くと無駄に長くなるのでそれは別ファイルに分離。
APIモジュール
package API;
use strict;
use warnings;
use utf8;
sub top {
my ($req) = @_;
my $res = $req->new_response(200);
$res->content_type('text/html');
$res->body('Hello');
return $res;
}
1;
実処理を記述するファイル。
今回は単純にHelloを返すだけにする。
戸惑った点
開発環境の用意
今まで、PHPやJSぐらいしか書いてこなかったため、エディタや強力なIDEがある環境でやってきたのだけど、いざperlを書こうとした時に良さげなエディタを見つけられずvimで書くことにした。
今までvimも単純にコピペぐらいでしか使っていなかったため、なかなか慣れずに一連のファイルを作るだけでも意外と苦労した。
モジュールのインストール
composerやnpmなんかは配布されているモジュールをインストールするだけなのだが、今回はインストール時にモジュールのテストも行うため、インストールに非常に時間がかかった。
testを無効にできると知ったのは後の祭り。