GraphQL Inputは同じ関心事で1つのtypeにまとめるのが良いプラクティス
例えば住所
city,town,postalcodeなどはAddressというtypeにまとめる
こうすることで、cityはあるのにpostalcodeはない、のような矛盾を防げる
ProductionReadyGraphQL参照
住所入力フォームが、それ以外(例えば氏名、年齢、電話番号等)の情報とセットで送られてくるとする
`input { address: AddressInput name: String! age: Number! phone: String! }`
この場合、フロントエンド上のオブジェクト構造ではこうなる
`{ address?: { postalCode: string; city: string; town: string; }; name: string; age: number; phone: string; }`
これをフォームに対応付けると、各要素のname属性はどうなるか
`address.city` のようにドット繋ぎになる?
`addressCity` のようにキャメルケースでまとめる?
どちらのパターンも、GraphQL SchemaからZod Schemaを生成した場合苦労する
Zod Schemaはネストされた構造を `ZodLazy` で表現する
`{ address: z.lazy(() => AddressInput()) }`
`city` にバリデーションをかけるには、`city` に突き当たるまで再帰的に `shape` で取り出したのちに `pick` する必要がある
つまり `address.city` をsplitして `shape[currentPath]` みたいに降りていく
しかし、`z.lazy` された要素は `shape` で取り出すことはできない
実行されるまで `shape` が定まらないため
同様に、`nullish()` された場合も `ZodOptional` となり `shape` を参照できない
`addressCity` 形式の場合、そもそもパースすること自体難しい
`addressCity: z.string()` のようなスキーマを別途手書きすることになる
自動生成の意味がない
結局、GraphQL Inputのネストした構造自体がフォームバリデーションと相性が悪いのでは?
blur等で特定の要素のみがきた場合も、古いフォームオブジェクトにマージして全体をバリデーションする等すれば可能かもしれない
pickが難しいという話なので、全体構造を保っていれば良い
だとしても、ZodSchemaのネスト構造をGraphQLErrorのextensionsが持つpathパターン(address.city)にマッピングしなおす({ "address.city": { errors: [{ message: "..." }] } })ことは必要になり、つらい