tokuhirom's Blog

Web Application の validation はどのレイヤーでかけるべきか

数年前にも同じことかいた気がするけど、最近の状況にあわせてかいてみる。 途中で面倒になってきて説明が雑になっている点をご容赦ください。


言いたいことは「結局、昔はサーバサイドで懇切丁寧なエラーメッセージを出すためにModelではなくControllerでバリデーションに関する知識が必要だったけど 今はJavaScriptでやるから不要だよね111」ってことです。


この表題は、よく話題にあがるところなのだが、理想論としては Model, Controller, Client side のいずれにおいてもきっちりと validation を行うことがのぞましい。

しかし、実際にはなかなか面倒である。ということで、どこをはぶくかというと Controller における Validation であろう。

ユーザーに対する親切なメッセージは JS の側でだすのが理想的。model の validation が必須なのはいうまでもない。


最近は model layer で Data::FormValidator で validation をかけてる。


エンドユーザーが利用するフォームなどの場合

基本丁寧に JS で validation を記述すればよい。それをぬけた場合に、親切なメッセージをだす必要が感じられるならば、controller での validation をかけてもよい。そのへんはコストとの相談だと思います。

基本的には model layer での validation にひっかかるようなリクエストが送られないように client side で処理しておくるようにすればいいかなーと。

自社の人間しか利用しない管理画面などの場合

HTML5 の form validation をもって client side の validation とする。入力のルール等は HTML 側に記述する。

server 側では model のレイヤーで validation を行い、ひっかかった場合には exception を throw する。どの項目がエラーになってるかぐらいは表示するようにしている。基本的にはそこの例外があがるケースはあまりないのでいいかな、と。

D::FV で書くのが面倒な部分は logic を perl でかいて、fail する部分は例外をあげてる。

JSON API での validation

広くユーザーにつかわせる場合はかっちりやったらよい。controller での validation やったほうがいい。

自社製の iPhone app / Android app / web app のみが対象の場合、controller での validation はそこまでかっちりやる必要がない。連絡を密にとれるからだ。model と JSON API の end point は 1 対 1 で大概の場合は対応するだろうから、model で validation して例外があがればわりと十分なかんじがする。

model での validation が fail すると例外あがって、なんか 403 とかかえるようにしとけばいい。

コントローラ実装例

sub create {
    my ($class, $c) = @_;

    MyApp::M::Item->create({
        $c->req->capture_params(qw(name)),
        member_id => $c->member->id,
    });
    return $c->render_json({});
}

コントローラ実装例(2)

sub create {
    my ($class, $c) = @_;

    my $params = {
        $c->req->capture_params(qw(name)),
        member_id => $c->member->id,
    };
    MyApp::M::Item->validate('create', $params)
        or return $c->make_simple_response(403);
    MyApp::M::Item->create($params);
    return $c->render_json({});
}

まとめ

ユーザーエクスペリエンスを損なわない範囲において、楽したい。