
Summary
この文書の要点
- 画面の一時入力とAPIの確定入力は別の型として考える。
- 文字列から数値や日付への変換を明示する。
- 入力中の文字列、正規化後の値、保存用DTOを分けてschema化する。
- フロントエンドとAPIで同じschemaを使う場合も、エラー表示の責務は分ける。
どこが設計の難所か
フォームでは未入力、入力途中、不正な文字列を一時的に保持します。一方でAPIは確定した型を受け取りたいです。同じZodスキーマを両方に使うと、入力途中の状態を扱いづらくなることがあります。
ブラウザの入力値は基本的に文字列です。数値、日付、チェックボックス、複数選択などは変換が必要です。また、フロントエンドで通った検証でも、API側で再検証しない設計は安全ではありません。
フォーム検証をZodで共有すると、重複を減らせます。一方で、フォームでは空文字、未選択、入力途中の不完全な値を扱います。API側の保存schemaだけをそのまま使うと、入力体験が硬くなります。
境界をどう切るか
スキーマは、フォーム状態用、送信用、API受信用に分けることを検討します。共通化するのは項目名や基本制約に留め、画面固有の入力途中状態や表示メッセージはフロント側で扱います。
設計では、form schema、normalized schema、API schemaを分けます。React側は入力中の緩い状態を許容し、送信時に正規化してAPI schemaへ渡します。API側は信頼せず再検証します。
実装で効く細部
Zodではpreprocessやtransformを使えますが、変換と検証を混ぜすぎると見通しが悪くなります。まず入力文字列を正規化し、その後に業務ルールを検証します。APIでは受信時に同じ制約を改めて確認します。
実装では、日付、数値、チェックボックス、selectの空値を正規化する関数をschemaの外側またはpreprocessとして整理します。サーバーエラーはfield pathを持たせ、フォームライブラリが表示位置へマッピングできる形にします。
- 空文字をundefined、null、0のどれにするかを項目ごとに決める。
- Zodのrefineで業務ルールを入れすぎず、DB参照が必要な検証はAPI側で行う。
- エラーメッセージはschemaの都合ではなく、利用者が直せる言葉にする。
壊れ方を観測する
検証では、空文字、全角数字、日付形式、境界値、配列の空、不要フィールドを確認します。エラー表示は項目ごとに利用者が修正できる文言になっているかも見ます。
検証では、入力途中、送信前、API拒否、サーバーエラー反映を分けて確認します。型が通るだけでなく、画面でどの項目にどのエラーが出るかをテストすると実用性が上がります。
捨てた選択肢とトレードオフ
スキーマを分けると重複が増えます。完全共有を目指すと画面状態が窮屈になります。共有すべき制約と、画面やAPIに固有の制約を分けるのが実用的です。
schema共有を徹底すると重複は減りますが、画面ごとの入力体験を表現しづらくなります。完全共有ではなく、共通の基礎schemaから画面用とAPI用を派生させる方が扱いやすいです。
現場に残す判断軸
Zodの価値は、何でも一つのスキーマにすることではありません。入力途中、送信、保存の各段階を意識して検証を分けることで、型安全性と使いやすさを両立できます。
Zod共有の目的は、同じschemaをどこでも使うことではありません。入力中と保存時の境界を明確にし、正規化と検証を分けることが、壊れにくいフォームにつながります。


