やりたいこと
zod や valibot で "true"
, "false"
を boolean の true
, false
に 変換 しつつ validation
valibot ・ zod とは
どちらもランタイム時にvalidationを行うライブラリで、valibotの方が後出です。
現時点では、valibotは出て半年も経っていないので、zodが広く使われています。
valibot
は zod
と似たような定義の方法とメソッド名で、スキーマを定義でき軽量なのが特徴です。
zodと比較すると、バンドルサイズは約半分ぐらいなんだそうです。
背景
nextjs の server actions を使っていると、schema は boolean
だけども、FormDataから送信するときには、string
にしないといけない場合がでてきました。
action送信時に、"true"
, "false"
を boolean の true
, false
に変換が必要になったので zod
と valibot
で変換してみました。
どちらもschema
をちょっと変更するだけで出来ました。
例
例えば、Todoアプリがあるとして、下記のようなschema
だったとします。
zodの場合
import { z } from 'zod';
const TodoSchema = z.object({
id: z.string(),
title: z.string(),
description: z.string(),
completed: z.boolean(),
});
valibotの場合
import { boolean, object, string } from 'valibot';
export const TodoSchema = object({
id: string(),
title: string(),
description: string(),
completed: boolean(),
});
validationするデータ
{
id: '548a7df1-2dc6-47db-9ad4-2c5c955966d2',
title: 'ゴミ捨て',
description: '水曜ねー',
completed: 'false' // 文字列で来てしまう
}
FormDataから取得するとboolean
は文字列になっているので、これを変換し、validation
します。
string → boolean に parse
zodの場合
import { z } from 'zod';
const TodoSchema = z.object({
id: z.string(),
title: z.string(),
description: z.string(),
- completed: z.boolean(),
+ completed: z.preprocess((input) => JSON.parse(`${input}`), z.boolean()),
});
const validated = TodoSchema.parse({
id: '548a7df1-2dc6-47db-9ad4-2c5c955966d2',
title: 'ゴミ捨て',
description: '水曜ねー',
completed: 'false'
});
{
id: '548a7df1-2dc6-47db-9ad4-2c5c955966d2',
title: 'ゴミ捨て',
description: '水曜ねー',
completed: false
}
valibotの場合
import { boolean, object, string, coerce, parse } from 'valibot';
const TodoSchema = object({
id: string(),
title: string(),
description: string(),
- completed: boolean(),
+ completed: coerce(boolean(), (input) => JSON.parse(`${input}`)),
});
const validated = parse({
id: '548a7df1-2dc6-47db-9ad4-2c5c955966d2',
title: 'ゴミ捨て',
description: '水曜ねー',
completed: 'false'
});
{
id: '548a7df1-2dc6-47db-9ad4-2c5c955966d2',
title: 'ゴミ捨て',
description: '水曜ねー',
completed: false
}
ポイント
- zod: preprocessを使用
- valibot: coerceを使用
-
JSON.parse
を使って、文字列・boolean値のどちらにも対応
JSON.parse("true"); // => true
JSON.parse("false"); // => false
JSON.parse(true); // => true
JSON.parse(false); // => false
これで、大きな変更なく、値の変換 と validation
が 両立できました。