mojoliciousでつくる! webアプリ入門
DESCRIPTION
YAPC::Asia 2013 2013/09/21 Yusuke Wada a.k.a. yusukebeTRANSCRIPT
![Page 1: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/1.jpg)
Mojoliciousでつくる!Webアプリ入門
2013/09/21YAPC::Asia 2013
Yusuke Wada a.k.a. yusukebe
Some papix photos are in this slides. Thanks to papix!
![Page 2: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/2.jpg)
イントロダクション
![Page 3: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/3.jpg)
自己紹介
• 和田裕介 1981/12/23 生• 慶應義塾大学制作メディア研究科修了• 株式会社ワディット代表取締役• 株式会社オモロキ取締役兼最高技術責任者• http://yusukebe.com/ or @yusukebe
![Page 4: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/4.jpg)
メインワーク
![Page 5: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/5.jpg)
問いかけ
![Page 6: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/6.jpg)
Perlは大規模Webサービスで使われているが...
初心者がWebアプリに入門する資料が少ない...?
![Page 7: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/7.jpg)
あえて去年を振り返る
「新しい」を生み出すためのWebアプリ開発とその周辺
![Page 8: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/8.jpg)
何をつくるかは分かった
そのための実装について
本日の主題
![Page 9: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/9.jpg)
対象オーディエンス
• Webアプリケーションをつくりたい方• アイデアはあるが実装できない... って方• 最近のWAFについて知りたい方
• Web Application Framework = WAF• Mojoliciousを使った具体的なアプリ構成を知りたい方
![Page 10: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/10.jpg)
方針
当たり前に使っている概念、実装、キーワード
噛み砕いて解説
=> GoogleやCPANで検索できるように!
実はすごく周辺からは分かりにくい...?
![Page 11: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/11.jpg)
アジェンダ• 例題:占いアプリについて• WebアプリケーションとFramework• Mojoliciousの紹介• Mojolicious::Liteを使う• より実践的なアプリへ• CPANモジュールとの組み合わせと工夫• 今後へ
![Page 12: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/12.jpg)
0. 例題:占いアプリについて
![Page 13: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/13.jpg)
名前に応じて占い結果を出す• 占い結果はまず3種類• 良い事が起こるでしょう• 出会いがあるかも?• 不幸になります• 入力された名前に対して必ず同じ結果• yusukebe => 「出会いがあるかも?」
![Page 14: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/14.jpg)
ハッシュ関数my $name = "yusukebe";my $max = 3;my $number = 0;
# 文字列を一文字ずつ分解for my $char (split //, $name) { # 文字に対応する数値を得る $number += ord $char;}
# 想定される最大値で割った余りを得るmy $result = $number % $max;print "$result\n";
文字列
数値
固定値で割る
余りが結果
![Page 15: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/15.jpg)
スクリプトで実現する
ようは診断メ○カーみたいな?
![Page 16: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/16.jpg)
1. WebアプリケーションとFramework
![Page 17: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/17.jpg)
Webアプリケーションを定義する
Webが誰かと特徴的なインタラクション
をする場合
Webアプリケーション
![Page 18: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/18.jpg)
Webのインタラクション
Webアプリケーション
ユーザー例えば自分の名前を
入力する
占いの結果を見る
JSの動作外部のWeb APIミドルウェア etc.
ブラウザプログラムスマホアプリ
![Page 19: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/19.jpg)
Web Application Framework• 通称 WAF(ワッフ)• 例えば Ruby on Rails• Webアプリケーションをつくるための土台• MVCモデルに基づく場合が多い
MVCってなんぞー?
![Page 20: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/20.jpg)
Model
View
Controller
MVC
MVCである意味は...?
![Page 21: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/21.jpg)
MVC以前
![Page 22: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/22.jpg)
何がイケてないって?• 色々混じってる• ヘッダー出力• ロジック処理• HTMLの描画• ファイルごとにルーティングする• 重複が起こる
*CGIはデプロイ方法の一つなのでCGI自体が良くないわけではない
![Page 23: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/23.jpg)
愚直に.cgiを書くとuse CGI qw/param header/;
my $name = param('name');my @list = qw/良い事が起こるでしょう 出会いがあるかも? 不幸になります/;my $num = 0;$num += ord ($_) for split //, $name;my $index = $num % scalar @list;my $message = $list[$index];
print header('text/html; charset=utf-8');print "<html><body>";print "<center><b>$message</b></center>";print "</body></html>";
![Page 24: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/24.jpg)
HTMLだけでも分離させると...use CGI qw/param header/;use Text::MicroTemplate qw/render_mt/;use Data::Section::Simple qw/get_data_section/;
my $name = param('name');my @list = qw/良い事が起こるでしょう 出会いがあるかも? 不幸になります/;my $num = 0; $num += ord ($_) for split //, $name;my $index = $num % scalar @list;my $message = $list[$index];
my $template = get_data_section('index.mt');my $html = render_mt($template, $message)->as_string();print header('text/html; charset=utf-8');print $html;
__DATA__
@@ index.mt<html> <body> <center><b><?= $_[0] ?></b></center> </body></html>
![Page 25: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/25.jpg)
冗長になるが見通しがよくなる!
さらにテンプレートをファイルに分けると...
メンテナンス性、再利用性の向上
冗長性はフレームワークが吸収してくれる?
![Page 26: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/26.jpg)
とりあえずMVCで考える意味• 混在している固まりを役割で分ける• 理解をすれば冗長になるが開発効率が上がる
![Page 27: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/27.jpg)
"分けるとは分かること"
![Page 28: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/28.jpg)
切り分け方
1. Router
2. Controller
3. Model / Logic
4. DB層 / OR Mapper
5. View / Static files
ビジネスロジックを扱う
出力や見た目に関する部分
個別のリクエストに基づく処理
データベースにまつわる
URL/METHODに応じて振り分ける
![Page 29: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/29.jpg)
役割を分けること =
フレームワーク的思考へ
![Page 30: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/30.jpg)
処理の流れ
Router
Controller
Model / Logic
DB / OR Mapper
View
1. リクエスト
2. ディスパッチ
3. モデル呼び出し
4. DB呼び出し 5. DB結果返却
6. 結果
7. レンダリング
8. HTMLなど
9. レスポンス
![Page 31: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/31.jpg)
PerlのWAF達• Catalyst• Dancer• Amon2• Kossy• Pickles• Voson• Mojolicious• 自作WAF
![Page 32: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/32.jpg)
自作WAFと既存WAF• MVC?を実現するモジュールは揃っている• Plack::Request• Router::Simple• Text::Xslate• ただアプリを書きながらWAFもはキツい• 勉強用に車輪の再発明は多いに歓迎• でもとりあえずWAFを使いましょうね ♥
![Page 33: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/33.jpg)
2. Mojoliciousの紹介
![Page 34: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/34.jpg)
Mojolicious !• 属に言う「軽量WAF」の一種• 最新Ver.は「4.35」2013年9月12日時点• 作者は「Sebastian Riedel」氏
![Page 35: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/35.jpg)
特徴1. VCだけサポート• Routing / Controller• デフォルトではMojo::Templateを使うView• のみサポートし「Model」は対象外
Mojo::Baseその他でクラスつくったりOR Mapper
使ったりして自力で実装してね ♪ っていう...
逆にそれがいいModel/Logic層はWebから切り離すべき
![Page 36: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/36.jpg)
特徴2. Not full-stack but full-stackRuby on Rails
DBを扱うまで全てこれ一つで出来る フルスタック
MojoliciousHTTPのRequestやUserAgentまでMojoliciousで使うライブラリが全て自作 フルスタック
コア以外のCPANモジュールに依存しない!
![Page 37: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/37.jpg)
![Page 38: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/38.jpg)
$ cpanm Mojolicious
![Page 39: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/39.jpg)
Mojoliciousなら一発
![Page 40: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/40.jpg)
特徴3. その他• アップデートが頻繁
$self->render_json( $ref ); # 4.00 で廃止# => $self->render( json => $ref );
ただし依存が無いのでMojoliciousだけ追っていればよい
• Mojolicious::Lite を使えばファイル一つで• 工夫すればCGIでも動作可能• Perl 5.10.1 以上必須、5.16 以上を推奨• 開発用サーバmorbo、本番用hypnotoad• もちろんPSGI互換
![Page 41: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/41.jpg)
小さなアプリから大きなWebアプリまで
徐々に学べるフレームワークMojolicious::Lite
MojoliciousCPANモジュールの組み合わせ
![Page 42: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/42.jpg)
3. Mojolicious::Liteを使う
![Page 43: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/43.jpg)
mojoコマンドによるスケルトン
$ mojo generate lite_app myapp.pl
Mojolicious::Lite
![Page 44: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/44.jpg)
はじめてのMojolicious::Lite#!/usr/bin/env perluse Mojolicious::Lite;
get '/' => sub { my $self = shift; $self->stash->{message} = 'Hello Mojo!'; $self->render('index');};
app->start;__DATA__
@@ index.html.ep<html> <body> <p><%= $message %></p> </body></html>
Controllerに該当
View(テンプレート)
Routingしてる
![Page 45: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/45.jpg)
立ち上げ方
$ morbo -l "http://*:5000" myapp.pl
morboを使う
$ plackup -p 5000 myapp.pl
plackupで立ち上げる
![Page 46: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/46.jpg)
Hello World から学ぶ
get '/' => sub {};
ルーティングとコントローラ
GET http://localhost:5000/
get '/entry/:id' => sub { my $entry_id = $self->stash->{id};};
post '/entry' => sub {};POST http://localhost:5000/entry
GET http://localhost:5000/entry/1
![Page 47: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/47.jpg)
Hello World から学ぶ
get '/' => sub { my $self = shift; $self->stash->{message} = 'Hello Mojo'; ...;}
テンプレートにデータを渡す
$self->render('index'); # index.html.ep を描画...;<p><%= $message %></p>
テンプレートの記述とレンダー
![Page 48: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/48.jpg)
もちろん占いアプリも!
![Page 49: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/49.jpg)
Short live coding !?
![Page 50: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/50.jpg)
#!/usr/bin/env perluse Mojolicious::Lite;use utf8;
...;
get '/' => sub { my $self = shift; $self->render('index');};
...;
@@ index.html.ep<p>名前を入力してください</p><form action="/result"> <input type="text" name="name" /> <input type="submit" value="占う" /></form>
トップページを描画
![Page 51: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/51.jpg)
...;
get '/result' => sub { my $self = shift; my $name = $self->req->param('name'); my @list = qw/良い事が起こるでしょう 出会いがあるかも? 不幸になります/; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @list; $self->stash->{message} = $list[$index]; $self->stash->{name} = $name; $self->render('result');};
...;
@@ result.html.ep<p><%= $name %>さんの結果「<%= $message %>」</p>
結果を出力
![Page 52: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/52.jpg)
Controller内での操作• 全ては「$self」のメソッドを扱うmy $value = $self->req->param('key');
$self->render('entry');
$self->render( json => { key => $value } );
Mojolicious::Controller を継承するのでそのドキュメントを読めばOK!
$self->redirect_to('/');
![Page 53: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/53.jpg)
Mojo::Template周り• Perl-ish templates => Perl書ける!% for my $entry (@$entries) { <h2><%= $entry->{title} %></h2>% }
Mojo::Template / Mojolicious::Plugin::DefaultHelper
• テンプレート向けhelper@@ index.html.ep% layout 'default';Hi, <%= $name %>
@@ layouts/default.html.ep<html> <body><%= content %></body></html>
![Page 54: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/54.jpg)
Mojolicious::Liteアプリを拡張する
• public/ => 静的ファイルを置く• templates/ => テンプレートファイルを独立
./!"" myapp.pl!"" public/# !"" css/# !"" favicon.ico# !"" images/# %"" js/%"" templates/ !"" layouts/ # %"" default.html.ep %"" root/ %"" index.html.ep
![Page 55: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/55.jpg)
4. より実践的なアプリへ
![Page 56: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/56.jpg)
Mojolicious::Liteだと1ファイルがでかくなるよー
そこで ::Lite じゃないMojoliciousアプリ!
モジュールをいい感じに分けてつくれる
![Page 57: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/57.jpg)
Mojoliciousアプリをつくるコツ• $ mojo generate app MyApp では無くMyApp::Web みたいなネームスペースで
$ mojo genearate app Uranai::Web
• なぜならUranaiがWeb層だけではないかも• Uranai::Model / Uranai::Logic• Uranai::CLI
![Page 58: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/58.jpg)
だいたいこんな構成./!"" Uranai/# !"" DB/# # %"" Schema.pm# !"" DB.pm# !"" Model/# # %"" OneModel.pm# !"" Web/# # %"" Controller/# # %"" Root.pm# %"" Web.pm%"" Uranai.pm
DBレイヤー / Teng etc.
ビジネスロジック / Perl Module
Webレイヤー /主にControllerとルーティング
Uranai.pm では パス解決と設定ロードを実装
![Page 59: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/59.jpg)
::Liteからの移行#!/usr/bin/env perluse Mojolicious::Lite;
get '/' => sub { my $self = shift; $self->stash->{message} = 'Hello Mojo!'; $self->render('index');};
app->start;__DATA__
@@ index.html.ep<html> <body> <p><%= $message %></p> </body></html>
lib/Uranai/Web.pm
lib/Uranai/Web/Controller/*
Mojolicious::Controllerを継承
templates/
Mojo::Templateに準ずる
![Page 60: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/60.jpg)
すんなり移行出来る!
![Page 61: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/61.jpg)
占いアプリを実装してみる
![Page 62: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/62.jpg)
実装方針
• 占いのロジック部分をModelとして切り出す• Uranai::Model::Uranai• それをControllerから適宜呼び出す• ViewはMojolicious::Liteと同じものを別ファイルにする
![Page 63: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/63.jpg)
Uranai::Model::Uranaipackage Uranai::Model::Uranai;use Mouse;
has 'list' => ( is => 'ro', isa => 'ArrayRef[Str]', default => sub { [qw/良い事が起こるでしょう 出会いがあるかも? 不幸になります /]});
sub uranau { my ($self, $name) = @_; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @{$self->list()}; return $self->list->[$index];}
__PACKAGE__->meta->make_immutable();
![Page 64: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/64.jpg)
ModelはCLIからも使える
use Uranai::Model::Uranai;use feature 'say';
my $uranai = Uranai::Model::Uranai->new;say $uranai->uranau('yusukebe');
ってことは単体でテスト出来る!
![Page 65: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/65.jpg)
Uranai::Web::Controller::Rootpackage Uranai::Web::Controller::Root;use Mojo::Base 'Mojolicious::Controller';use Uranai::Model::Uranai;
sub index { my $self = shift; $self->render('index');}
sub result { my $self = shift; my $name = $self->req->param('name'); return $self->redirect_to('/') unless $name; my $uranai = Uranai::Model::Uranai->new; my $message = $uranai->uranau($name); $self->stash->{message} = $message; $self->render('result');}
1;
![Page 66: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/66.jpg)
アプリをつくるフロー• Modelを書く• (テストする)• Routing / Controller を書く• テンプレートを書く• テストサーバを起動しておく• ブラウザで確認• 繰り返し...
![Page 67: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/67.jpg)
5. CPANモジュールとの組み合わせと工夫
![Page 68: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/68.jpg)
Mojoliciousだけでは足りない
• CPANモジュールを組み合わせてつくる• Like LEGO blocks
Mojolicious
OR Mapper FormValidator FillInForm etc.
![Page 69: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/69.jpg)
use FormValidator::Lite;• 入力値の妥当性をチェックする• 例:メールアドレス、郵便番号、文字数
FormValidator::Lite->load_constraints(qw/Japanese Email/);
my $validator = FormValidator::Lite->new($self->req);my $res -> $validator->check( name => [qw/NOT_NULL/], mail => [qw/EMAIL/], { mails => [qw/mail mail_confirm/] } => ['DUPLICATION']);if($validator->has_error) { $self->stash->{messages} = $validator->get_error_messages(); return $self->render;}...;
![Page 70: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/70.jpg)
use Teng;• データベースを操作する OR Mapper• とってもシンプル• Controllerからは操作せずModelから触る
my $teng = Teng::Schema::Loader->load( dbh => $dbh, namespace => 'Uranai::DB',);
my $row = $teng->insert(result => { text => 'あなたは結婚出来ません',});
![Page 71: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/71.jpg)
DBを用いた占いアプリの応用• 固定だった3つの選択肢を増やせるようにしたい
![Page 72: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/72.jpg)
ちなみにやったことCREATE TABLE result ( id INT UNSIGNED AUTO_INCREMENT, text VARCHAR(200) NOT NULL, created_at DATETIME NOT NULL, PRIMARY KEY (`id`));
1. DBをつくって...
lib/Uranai/DB.pmlib/Uranai/DB/Schema.pm
2. TengのDB/スキーマつくって...
lib/Uranai/Model/Uranai.pm
3. Modelから操作するようにして...
lib/Uranai/Controller/Root.pm
5. Controllerから呼び出す
templates/root/index.html.ep
6. Viewの変更
t/01_model.t
4. 簡単なテスト書いて...
できた!
![Page 73: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/73.jpg)
その他実践で使ってるモジュール• HTML::FillInForm::Lite• Data::Validator• Mouse• SQL::Maker• Carton• Devel::NYTProf / Devel::KYTProf• Test::mysqld• Harriet• Cinnamon• Server::Starter• Starman / Starlet• etc....
Thanks to great Module Authors !
![Page 74: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/74.jpg)
Tips
![Page 75: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/75.jpg)
DELETE/PUTを擬似的にサポートさせる$self->hook( before_dispatch => sub { my $c = shift; if($c->req->method eq 'POST' && $c->req->param('_method')) { my $methods = [qw/GET POST PUT DELETE/]; if ( grep { $_ eq uc $c->req->param('_method') } @$methods ) { $c->req->method( $c->req->param('_method') ); } } });
my $r = $self->routes;$r->delete('/entry/:id')-> to( controller => 'Entry', action => 'delete' );
![Page 76: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/76.jpg)
helperでFillInFormをお手軽に# Uranai::Web$self->helper( render_fill => sub { my ($self, $name) = @_; my $html = $self->render(template => $name, partial => 1); return $self->render( text => HTML::FillInForm::Lite->fill(\$html, $self->req->params), format => 'html' ); });
# Uranai::Web::Controller::*sub form { my $self = shift; ...; if ($validator->error) { $self->stash->{messages} = $validator->get_error_messages(); return $self->render_fill('form'); }}
![Page 77: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/77.jpg)
Uranai->config();
# Uranai
sub config { my $mode = $ENV{PLACK_ENV} || 'development'; my $fname = File::Spec->catfile( Uranai->base_dir() , $mode . '.pl' ); my $config = undef; if( -f $fname ){ $config = do $fname or die "Cannnot load configuration file: $fname"; }else{ die "Cannot find configuration file: $fname"; } return $config;}
![Page 78: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/78.jpg)
Mojoliciousのセッションについて
• デフォルトはクライアントにクッキーとして保持• 気に入らない場合は...• Plack::Middleware::Session• 自作セッション管理
![Page 79: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/79.jpg)
6. 今後へ
![Page 80: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/80.jpg)
紹介したこと
• WAFとMVC的な構成について• 役割を適切に分けることでスッキリと• 対応するMojoliciousを使った実装• 占いアプリを例にあげた
![Page 81: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/81.jpg)
Webアプリをつくるには?• 例えば今回の占いアプリ• Mojolicious::Liteで実装してみる• 出来た!俺ってばスゲー体験 その1• Mojoliciousアプリで拡張してみる• 出来た!俺ってばスゲー体験 その2• Tengを学習し占いのパターンを増やす• 出来た!俺ってばスゲー体験 その3
![Page 82: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/82.jpg)
俺ってばスゲー体験
少しずつ"動いて" "分かる"
![Page 83: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/83.jpg)
扱わなかった主な点• よりツッコんだMojoliciousの使い方• テスト => Test::More / Test::Mojo• 生に近いDB/SQL操作• その他ミドルウェア => memcached / Redis• デプロイ => サーバ構成 / アプリサーバ• パフォーマンス計測、チューニング• Perl以外のこと => JavaScript / CSS / HTML
![Page 84: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/84.jpg)
まとめ
![Page 85: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/85.jpg)
Mojoliciousではじめよう
• 薄いWAFゆえ理解しやすい• Mojolicious::Lite のように少しずつつくれる• 他のWAFにも応用出来る
徐々に学べるフレームワーク
![Page 86: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/86.jpg)
キーワードは...
分けることで分かる
少しずつやろう
![Page 87: Mojoliciousでつくる! Webアプリ入門](https://reader031.vdocuments.net/reader031/viewer/2022013114/540d06107bef0ad7288b8fe7/html5/thumbnails/87.jpg)
終わり
ご質問は個別に!