joi vs yup vs superstruct vs runtypes vs io-ts vs zod
データ検証とスキーマ定義
データ検証とスキーマ定義
データ検証とスキーマ定義ライブラリは、JavaScriptやTypeScriptアプリケーションでデータの整合性を確保するためのツールです。これらのライブラリは、外部から受け取るデータ(例えば、APIリクエストやフォーム入力)が期待される形式や構造に従っているかを検証します。これにより、不正なデータがアプリケーションに入るのを防ぎ、バグを減らし、セキュリティを向上させることができます。各ライブラリは異なるアプローチや機能を提供しており、プロジェクトのニーズに応じて選択することが重要です。例えば、joiやyupは宣言的なスキーマ定義を提供し、複雑なネストやカスタム検証が容易です。一方、io-tsやruntypesはTypeScriptの型システムと統合されており、ランタイムでの型検証を行いながら静的型チェックも可能です。
機能比較: joi vs yup vs superstruct vs runtypes vs io-ts vs zod
型安全性
- joi:
joiは、型安全性を提供しますが、TypeScriptとの統合はio-tsほど強力ではありません。スキーマ定義は柔軟ですが、型情報は手動で管理する必要があります。
- yup:
yupは、型安全性を提供しますが、TypeScriptとの統合は限定的です。スキーマ定義は柔軟ですが、型情報は自動的には生成されません。
- superstruct:
superstructは、型安全性を提供しますが、TypeScriptとの統合は他のライブラリほど強力ではありません。型定義は明示的ですが、ランタイムでの型検証は手動で行う必要があります。
- runtypes:
runtypesは、TypeScriptの型情報を活用したランタイム検証を提供します。型定義と検証が明確に分かれており、型安全性が高いです。
- io-ts:
io-tsは、TypeScriptの型システムと密接に統合されており、型安全なランタイム検証を提供します。型定義と検証ロジックを一元管理できるため、型情報を活用した検証が可能です。
- zod:
zodは、TypeScriptファーストのライブラリで、スキーマから自動的に型を推論できます。型安全性が高く、型定義と検証が一貫しています。
非同期検証
- joi:
joiは非同期検証をネイティブでサポートしており、Promiseを返すカスタム検証が容易です。
- yup:
yupは非同期検証をネイティブでサポートしており、Promiseを返すカスタム検証が容易です。
- superstruct:
superstructは非同期検証をサポートしており、Promiseを返すカスタム検証関数を簡単に組み込むことができます。
- runtypes:
runtypesは非同期検証をサポートしていませんが、Promiseを返すカスタム検証関数を使用することは可能です。
- io-ts:
io-tsは非同期検証をサポートしていませんが、Promiseを返すカスタム検証関数を使用することは可能です。
- zod:
zodは非同期検証をサポートしており、Promiseを返すカスタム検証関数を簡単に組み込むことができます。
カスタム検証
- joi:
joiはカスタム検証を非常に強力にサポートしており、簡単にカスタム検証関数を作成してスキーマに組み込むことができます。
- yup:
yupはカスタム検証をサポートしており、カスタムバリデーション関数をスキーマに追加することが容易です。
- superstruct:
superstructはカスタム検証をサポートしており、カスタム検証関数を簡単に組み込むことができます。
- runtypes:
runtypesはカスタム検証をサポートしていますが、カスタム検証関数を手動で定義する必要があります。
- io-ts:
io-tsはカスタム検証をサポートしていますが、実装には少し手間がかかります。カスタムタイプを定義することで、独自の検証ロジックを組み込むことができます。
- zod:
zodはカスタム検証をサポートしており、カスタム検証関数を簡単にスキーマに組み込むことができます。
エラーメッセージのカスタマイズ
- joi:
joiはエラーメッセージのカスタマイズが非常に柔軟で、各検証ルールごとにカスタムメッセージを設定することができます。
- yup:
yupはエラーメッセージのカスタマイズが容易で、各フィールドや検証ルールに対してカスタムメッセージを設定することができます。
- superstruct:
superstructはエラーメッセージのカスタマイズが可能ですが、デフォルトのメッセージを上書きする必要があります。
- runtypes:
runtypesはエラーメッセージのカスタマイズが限られていますが、カスタムエラーメッセージを返すようにカスタム検証関数を設定することができます。
- io-ts:
io-tsはエラーメッセージのカスタマイズが難しいですが、カスタムエラーメッセージを返すようにカスタムタイプを設定することができます。
- zod:
zodはエラーメッセージのカスタマイズが可能で、各検証ルールに対してカスタムメッセージを設定することができます。
Ease of Use: Code Examples
- joi:
joiのカスタム検証の例
const Joi = require('joi');
// カスタム検証関数
const isPositive = (value, helpers) => {
if (value > 0) return value;
throw new Error('値は正の数でなければなりません。');
};
// スキーマの定義
const schema = Joi.object({
age: Joi.number().custom(isPositive, '正の数の検証'),
});
// 検証
const { error, value } = schema.validate({ age: -5 });
if (error) {
console.log('検証エラー:', error.message);
} else {
console.log('検証成功:', value);
}
- yup:
yupのカスタム検証の例
const yup = require('yup');
// カスタム検証関数
const isPositive = (value) => {
if (value <= 0) throw new yup.ValidationError('値は正の数でなければなりません。');
return value;
};
// スキーマの定義
const schema = yup.object().shape({
age: yup.number().custom(isPositive),
});
// 検証
schema.validate({ age: -5 }).catch((err) => {
console.log('検証エラー:', err.message);
});
- superstruct:
superstructのカスタム検証の例
import { struct } from 'superstruct';
// カスタム検証関数
const isPositive = (value) => {
if (value <= 0) throw new Error('値は正の数でなければなりません。');
return value;
};
// ストラクチャの定義
const User = struct({
age: 'number',
positiveAge: isPositive,
});
// 検証
try {
User({ age: 25, positiveAge: -5 });
} catch (error) {
console.log('検証エラー:', error.message);
}
- runtypes:
runtypesのカスタム検証の例
import { Runtype, Number, Record } from 'runtypes';
// カスタム検証関数
const isPositive = (n: number) => n > 0;
// カスタムタイプの定義
const PositiveNumber: Runtype<number> = Number.withConstraint(isPositive);
// スキーマの定義
const User = Record({
age: PositiveNumber,
});
// 検証
const result = User.validate({ age: 10 });
console.log(result);
- io-ts:
io-tsのカスタム検証の例
import * as t from 'io-ts';
import { isRight } from 'fp-ts/lib/Either';
// カスタム検証関数
const isPositive = (n: number) => n > 0;
// カスタムタイプの定義
const PositiveNumber = new t.Type<number, number, unknown>(
'PositiveNumber',
(u): u is number => typeof u === 'number' && isPositive(u),
(u, c) => (isPositive(u) ? t.success(u) : t.failure(u, c)),
t.identity
);
// 検証
const result = PositiveNumber.decode(10);
if (isRight(result)) {
console.log('検証成功:', result.right);
} else {
console.log('検証失敗:', result.left);
}
- zod:
zodのカスタム検証の例
import { z } from 'zod';
// カスタム検証関数
const isPositive = (value: number) => {
if (value <= 0) throw new Error('値は正の数でなければなりません。');
return value;
};
// スキーマの定義
const schema = z.object({
age: z.number().refine(isPositive, { message: '値は正の数でなければなりません。' }),
});
// 検証
schema.parse({ age: -5 });
選び方: joi vs yup vs superstruct vs runtypes vs io-ts vs zod
- joi:
joiは、柔軟で強力なスキーマ定義とデータ検証を提供します。ネストされたオブジェクトや配列の検証が得意で、カスタム検証やエラーメッセージのカスタマイズも容易です。特に、APIリクエストやフォームデータの検証に広く使われています。
- yup:
yupは、Promiseベースの非同期検証をサポートし、スキーマのチェーンメソッドによる定義が特徴です。特に、フォームバリデーションや非同期検証が必要な場合に便利です。カスタムバリデーションやエラーメッセージの設定も柔軟に行えます。
- superstruct:
superstructは、シンプルで直感的な構文を持つデータ検証ライブラリです。構造体(struct)という概念を用いて、ネストされたデータの検証を簡潔に定義できます。特に、軽量で使いやすいライブラリを求める開発者に適しています。
- runtypes:
runtypesは、TypeScriptの型情報を活用した軽量なランタイム型検証ライブラリです。型安全性を保ちながら、シンプルなAPIでデータの検証を行いたい場合に適しています。特に、型定義と検証が明確に分かれているため、可読性が高いのが特徴です。
- io-ts:
io-tsは、TypeScriptの型システムと統合されたランタイム型検証を提供します。型安全性を重視し、型定義と検証ロジックを一元管理したい場合に適しています。特に、型情報を利用して自動的に検証を行いたいプロジェクトに向いています。
- zod:
zodは、TypeScriptファーストのスキーマ定義ライブラリで、型安全性を重視しています。スキーマから自動的に型を推論できるため、型定義と検証が一貫しています。特に、シンプルで直感的なAPIを求めるTypeScript開発者に適しています。
joi のREADME
joi
The most powerful schema description language and data validator for JavaScript.
Installation
npm install joi
Visit the joi.dev Developer Portal for tutorials, documentation, and support
Useful resources