😊
zodでスキーマが可変のときのバリデーションを実装する
テナントごとにデータのスキーマが違ったりするときに、zodでバリデーションを行えるのでは?と思い立ち試しにやってみたそれの備忘録です。
key-valueのペアからオブジェクトを作る
最初にkey-valueのペアの配列からオブジェクトを作れることを確認しました。以下のようにコードを書きました。
const inputs = [
{ key: "name", value: "Hanako" },
{ key: "age", value: 25 },
{ key: "email", value: "hanako@example.com" },
];
const obj = inputs.reduce((acc, { key, value }) => {
acc[key] = value;
return acc;
}, {} as Record<string, unknown>);
console.log(obj);
出力結果は以下です。console.log(obj.name);このように指定することもできたので、オッケーです。
{
name: "Hanako",
age: 25,
email: "hanako@example.com",
}
zodで可変なz.objectを作る
以下のようにコードを書きました。key-valueのペアのkeyはさっきと変わらずで、valueにzodの型スキーマを指定しました。また、z.object()内で、reduceを利用してオブジェクトの型スキーマを構築しています。
const inputsType = [
{ key: "name", value: z.string() },
{ key: "age", value: z.number().int() },
{ key: "email", value: z.email() },
];
const schema = z.object(
inputsType.reduce((acc, { key, value }) => {
acc[key] = value;
return acc;
}, {} as Record<string, z.ZodTypeAny>)
);
const inputData = {
name: "Hanako",
age: 25,
email: "hanako@example.com",
}
const result = schema.safeParse(inputData);
console.log(result);
console.log(result.success);
console.log(result.data);
console.log(result.error);
実行結果は以下です。
{
success: true,
data: {
name: "Hanako",
age: 25,
email: "hanako@example.com",
},
}
true
{
name: "Hanako",
age: 25,
email: "hanako@example.com",
}
undefined
こんな感じの書き方もできます。
const entries = [
["name", z.string()],
["age", z.number().int()],
["email", z.email()],
] as const;
type Entry = typeof entries[number];
type Shape = { [K in Entry as K[0]]: K[1] };
const shape = Object.fromEntries(entries) as unknown as Shape;
const schema = z.object(shape);
const inputData = {
name: "Hanako",
age: 25,
email: "hanako@example.com",
}
const result = schema.safeParse(inputData);
console.log(result);
console.log(result.success);
console.log(result.data);
console.log(result.error);
この書き方だとキーを保持できるのですが、テナントごとにスキーマが違うとなればキーを保持できるというメリットは少ないと思います。(ロマンは感じますが)
最後に
これができるとマルチテナントなアプリケーションでテナントごとに入力が違うシーンなどで役立つかもしれません。
Discussion