仕組みから学ぶ Web
応用読了目安 15 分#フォーム#バリデーション#二重送信#アクセシビリティ#UX

フォームと入力の検証 — 画面の検証は親切、サーバーの検証は守り

申し込みフォームで、送信ボタンを 2 回押した人に申し込みが 2 件でき、エラーで戻った人の入力は全部消えていた。画面の検証を足しても、サーバーを通る値は守れない。役割の違う 2 つの検証を、別のものとして設計する。

この記事の進み方

What — 2 つの検証は、役割が違う

フォームの検証には、画面(ブラウザ)での検証と、サーバーでの検証があります。似たことを確かめますが、目的が違います。

画面の検証サーバーの検証
目的利用者を助ける。間違いを早く知らせるデータを守る。不正な値を入れない
すり抜けられるかすり抜けられる(開発者ツール・直接の送信)すり抜けられない(最後の関門)
無くてもよいか無くても動く(不親切になるだけ)無いと、何でも入る
確かめられること形(空欄・書式・範囲)形に加えて、DB と照らすこと(満席・重複・権限)

画面の検証は、利用者の手元で動くので、利用者が止められます。開発者ツールで送信の中身を書き換える、API を直接呼ぶ。どちらも画面の検証を通りません。だから、データを守るのはサーバーの検証だけです。

そして、満席かどうか、同じメールで申し込み済みかどうかは、DB を見ないと分かりません。画面では確かめようがない検証もあります。

Compare送信ボタンを押してから、何が起きるか

押したら送る。失敗したら画面を作り直す。

押す → 送る
(反応が遅い)
もう一度押す → もう一度送る
→ 申し込み 2 件

満席で失敗 → 画面を作り直す
→ 入力が全部消える
二重送信
起きる
失敗したときの入力
消える
作る手間
無い
不正な値
—
  • –冒頭の事故の 1 と 2。
  • –利用者は、押したのに反応が無ければ、もう一度押す。それは正しい行動。

同じフォームでも、送信中と失敗したときの扱いで、利用者の体験とデータが変わる。

確認 — ここまで読めたか

画面で参加人数を 1〜10 に制限しているのに、DB に「-3」が入っていました。直すべき場所はどこですか?

まず選ぶ(解答例は a〜d の記号で説明します)

エラーの見せ方

サーバーがエラーを返したとき、利用者が次に何をすればよいかが分かる形で見せます。

  • 入力を消さない。長い備考を書き直させない
  • どの欄の問題かを、その欄のすぐ近くに出す。ページの上に「エラーがあります」とだけ出しても、長いフォームでは見つからない
  • 最初のエラーの欄に、カーソルを移す。画面を読み上げる道具を使う人にも、エラーがあったことが伝わる
  • 満席のように欄に紐づかないエラーは、フォームの上にはっきり出し、次の行動(キャンセル待ち・別の日程)を示す

エラー設計の記事で見たとおり、サーバーはどの欄の、どんな問題かを機械が読める形で返します。画面はそれを欄に振り分けて表示します。

Why — なぜ同じ検証を 2 回書くのか

同じ規則を 2 か所に書くのは、重複ではないのか

「参加人数は 1〜10」という規則を、画面とサーバーの両方に書くことになります。凝集度と結合度で見た「同じ知識を 2 か所に書かない」に反するように見えます。

実際、規則が 2 か所にあると、片方だけ変えるずれが起きます。上限を 20 に上げたのに画面だけ 10 のまま、など。これを避けるには、規則を 1 か所に書き、画面とサーバーの両方から使う形が理想です。同じ言語で書いているなら、検証の規則を共有できます。

共有できない場合は、サーバーを正にします。画面の検証がずれていても、困るのは親切さだけです。サーバーがずれると、データが壊れます。

反応が遅いと、人はもう一度押す

二重送信は、利用者の不注意ではありません。押したのに反応が無ければ、もう一度押すのが正しい行動です。原因は、押したことが伝わっていない画面の側にあります。

押した瞬間に「送信中」と表示してボタンを押せなくすると、押したことが伝わり、もう一度押す理由がなくなります。これは二重送信を減らすと同時に、体験そのものを良くします。

確認 — ここまで読めたか

二重送信を「どこから送られても」1 件にするために、必要なものはどれですか?

まず選ぶ(解答例は a〜d の記号で説明します)

演習 — まず自分で判断する

解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。

演習 — 設計判断を問う

冒頭の申し込みフォームを、どう直しますか?

与えられた条件
  • 二重送信の申し込みが月 40 件。送信ボタンを押してから応答まで 2〜3 秒かかる
  • 満席などでサーバーがエラーを返すと、入力がすべて消える
  • 参加人数に、負の数や 500 が入っている。画面では 1〜10 に制限している
  • フロントエンドとサーバーは、同じ TypeScript で書いている
この軸で考える
  • · データを守る検証はどこにあるか
  • · 二重送信を、画面とサーバーのどちらで、何のために防ぐか
  • · エラーのあと、利用者の入力と次の行動はどうなるか
まず選ぶ(解答例は a〜d の記号で説明します)

演習 — 説明できるか

「画面でしっかり検証しているから、サーバーの検証は最低限でいい」と言うフロントエンド担当に、サーバーの検証が要る理由を説明してください

与えられた条件
  • 相手は画面の検証を丁寧に作っていて、利用者の体験を大事にしている
  • 相手は、開発者ツールで送信の中身を書き換えられることを意識していない
  • 画面の検証の価値も認めたうえで話したい

読み終わりましたか?

読了にすると、これを前提とする記事がロードマップで開放されます。