概要
バリデーションとは「正しさを確認すること」ではない。
それは**“データが破壊しないこと、流通できること、意味があること”を保証する設計戦略**である。
バリデーションは「フロントで形式だけ」「バックでエラー時だけ」ではなく、
全層で意味を持ち、UI・状態管理・データ設計を貫く構造として設計されるべきものである。
本稿では、3階層の検証モデル、UI連携戦略、非同期検証、スキーマベースの共通化設計を解説する。
1. バリデーションの3階層モデル
1. 構文(Syntax)…形式の正当性(例:email, 数字)
2. 構造(Structure)…関連間の整合性(例:開始日 < 終了日)
3. 意味(Semantic)…業務的意味の正当性(例:未成年は契約不可)
→ ✅ チェック項目をこの3階層で分類し、責務を分離
2. 即時バリデーションとリアルタイムUX制御
<input
type="text"
value={email}
onChange={(e) => {
setEmail(e.target.value);
setError(validateEmail(e.target.value));
}}
/>
- ✅ 入力 → 即時検証 → UIエラー表示 = フローの一体化
- ✅ エラーは**「UI構造の一部」として設計**する
3. 非同期バリデーションの統合設計
async function checkEmailDuplicate(email) {
const res = await fetch(`/api/check?email=${email}`);
return res.ok ? await res.json() : { valid: false };
}
- ✅ 同期チェックと非同期チェックは構造的に合成可能に
- ✅ 非同期中の状態(loading)や pending 表示もUIに統合
4. スキーマベース設計(例:Zod / Yup / Joi)
import { z } from 'zod';
const userSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().min(18),
});
const result = userSchema.safeParse(formData);
if (!result.success) {
showErrors(result.error.format());
}
- ✅ UI / API / バックエンド で同一バリデーション構造を共有
- ✅ 安全な解析(safeParse)により破壊を防止
5. UIの状態とバリデーションの一体管理
const [form, setForm] = useState({ email: '', age: '' });
const [errors, setErrors] = useState({});
const validate = () => {
const result = schema.safeParse(form);
if (!result.success) setErrors(result.error.format());
return result.success;
};
- ✅ 入力値とバリデーション結果は状態として一体管理
- ✅ フォーム送信前・リアルタイムの2モード設計が基本
6. 複合ロジック・意味チェックの設計位置
if (user.age < 20 && user.plan === 'premium') {
errors.plan = '未成年はプレミアムプランに加入できません';
}
- ✅ 意味的チェックはドメインロジック or バリデータ層に委譲
- ❌ UI層に業務的ルールを埋め込まない
設計判断フロー
① 検証ルールが構文/構造/意味に分離されているか? → 責任分担の見直し
② UIで即時チェックが機能しているか? → 入力体験と整合性を確保
③ 非同期バリデーションの状態が破綻していないか? → 状態管理と統合
④ API層・UI層・ストア層でバリデーションが重複していないか? → スキーマ共通化へ
⑤ 意味的なチェックがUIに混在していないか? → ドメイン層での検証に抽出
よくあるミスと対策
❌ UIでのみチェック → APIに通って壊れるデータが流入
→ ✅ UIとAPIで同一スキーマ構造を適用
❌ 重複チェックが多重リクエストを生む
→ ✅ DebounceとAbortControllerで非同期制御設計
❌ バリデーションエラーが表示だけで済み、実行不能に
→ ✅ バリデーション状態 = 操作制御のロジックに直結
結語
バリデーションとは「正しいか」ではなく、
**“壊れない構造と、意味が通る世界を担保する設計層”**である。
- 構文・構造・意味の3階層で設計し
- UIと同期し、非同期も統合し
- スキーマで共有し、エラーを体験へ昇華する
JavaScriptにおけるバリデーション設計とは、
“データを守り、UIとロジックを信頼で繋ぐ構造戦略”である。