VineJS入門 — Node.jsの高速バリデーションライブラリ
VineJSとは
VineJSは、AdonisJS開発チームが開発した高速バリデーションライブラリです。Zodなどの既存ライブラリと比較して約14倍の処理速度を誇り、TypeScriptの型安全性も完全にサポートしています。
主な特徴
- 圧倒的な高速性: Zodと比較して14倍、Yupと比較して20倍高速
- TypeScript完全対応: スキーマから型を自動推論
- カスタマイズ可能: カスタムルール、カスタムメッセージ、多言語対応
- エラーハンドリング: 詳細なエラー情報を提供
- フレームワーク連携: AdonisJS、Honoなどで簡単に統合
インストール
npm install @vinejs/vine
TypeScriptプロジェクトでは追加の設定は不要です。
基本的な使い方
シンプルなスキーマ定義
import vine from '@vinejs/vine'
// スキーマ定義
const schema = vine.object({
email: vine.string().email(),
password: vine.string().minLength(8),
age: vine.number().min(18).optional(),
})
// バリデーション実行
const data = {
email: 'user@example.com',
password: 'securepass123',
}
try {
const validated = await vine.validate({ schema, data })
console.log('検証成功:', validated)
} catch (error) {
console.error('検証エラー:', error.messages)
}
型推論
VineJSはスキーマから自動的に型を推論します。
import vine, { Infer } from '@vinejs/vine'
const userSchema = vine.object({
name: vine.string(),
email: vine.string().email(),
isActive: vine.boolean(),
})
// 型を自動推論
type User = Infer<typeof userSchema>
// => { name: string; email: string; isActive: boolean }
const user: User = {
name: 'John Doe',
email: 'john@example.com',
isActive: true,
}
高度なバリデーション
ネストしたオブジェクト
const profileSchema = vine.object({
user: vine.object({
name: vine.string(),
email: vine.string().email(),
}),
address: vine.object({
street: vine.string(),
city: vine.string(),
zipCode: vine.string().regex(/^\d{3}-\d{4}$/),
}),
})
配列のバリデーション
const ordersSchema = vine.object({
userId: vine.string(),
items: vine.array(
vine.object({
productId: vine.string(),
quantity: vine.number().min(1),
price: vine.number().positive(),
})
).minLength(1),
})
条件付きバリデーション
const paymentSchema = vine.object({
method: vine.enum(['credit_card', 'bank_transfer']),
cardNumber: vine.string().optional(),
bankAccount: vine.string().optional(),
}).when('method', {
is: 'credit_card',
then: (schema) => schema.merge(vine.object({
cardNumber: vine.string().regex(/^\d{16}$/),
})),
otherwise: (schema) => schema.merge(vine.object({
bankAccount: vine.string(),
})),
})
カスタムバリデーションルール
独自のバリデーションロジックを追加できます。
import { VineString } from '@vinejs/vine'
// カスタムルール: 特定のドメインのみ許可
VineString.macro('allowedDomain', function (domains: string[]) {
return this.use((value, field, { errorReporter }) => {
const emailDomain = value.split('@')[1]
if (!domains.includes(emailDomain)) {
errorReporter.report(
field,
'allowedDomain',
`Email must be from: ${domains.join(', ')}`
)
}
})
})
// 使用例
const schema = vine.object({
email: vine.string().email().allowedDomain(['company.com', 'partner.com']),
})
カスタムエラーメッセージ
const messages = {
'email.required': 'メールアドレスは必須です',
'email.email': '有効なメールアドレスを入力してください',
'password.minLength': 'パスワードは8文字以上必要です',
}
const validated = await vine.validate({
schema,
data,
messages,
})
多言語対応
const jaMessages = {
'required': '{{ field }}は必須です',
'email': '有効なメールアドレスを入力してください',
'minLength': '{{ field }}は{{ min }}文字以上必要です',
}
const enMessages = {
'required': 'The {{ field }} field is required',
'email': 'Please enter a valid email address',
'minLength': 'The {{ field }} must be at least {{ min }} characters',
}
// 言語に応じて切り替え
const messages = locale === 'ja' ? jaMessages : enMessages
AdonisJSとの統合
AdonisJSではVineJSがデフォルトのバリデーターとして統合されています。
// app/validators/user_validator.ts
import vine from '@vinejs/vine'
export const createUserValidator = vine.compile(
vine.object({
email: vine.string().email().unique({ table: 'users', column: 'email' }),
password: vine.string().minLength(8),
name: vine.string().trim(),
})
)
// app/controllers/users_controller.ts
import { createUserValidator } from '#validators/user_validator'
export default class UsersController {
async store({ request, response }: HttpContext) {
const data = await request.validate(createUserValidator)
const user = await User.create(data)
return response.created(user)
}
}
Honoとの統合
HonoフレームワークでもVineJSを簡単に統合できます。
import { Hono } from 'hono'
import vine from '@vinejs/vine'
const app = new Hono()
const userSchema = vine.object({
name: vine.string(),
email: vine.string().email(),
})
app.post('/users', async (c) => {
const body = await c.req.json()
try {
const validated = await vine.validate({ schema: userSchema, data: body })
// ユーザー作成処理
return c.json({ success: true, user: validated })
} catch (error) {
return c.json({ success: false, errors: error.messages }, 400)
}
})
export default app
パフォーマンス比較
実際のベンチマーク結果(10,000回のバリデーション実行):
| ライブラリ | 実行時間 | Zodとの比較 |
|---|---|---|
| VineJS | 45ms | 14倍高速 |
| Zod | 630ms | 基準 |
| Yup | 910ms | 1.4倍遅い |
| Joi | 1,120ms | 1.8倍遅い |
VineJSは大量のバリデーションが必要なAPIサーバーやバッチ処理で特に威力を発揮します。
エラーハンドリング
VineJSは詳細なエラー情報を提供します。
try {
const validated = await vine.validate({ schema, data })
} catch (error) {
if (error instanceof errors.E_VALIDATION_ERROR) {
// フィールドごとのエラー
console.log(error.messages)
// [
// { field: 'email', message: 'The email field must be a valid email', rule: 'email' },
// { field: 'password', message: 'The password must be at least 8 characters', rule: 'minLength' }
// ]
// フラット形式
console.log(error.getFlat())
// {
// email: ['The email field must be a valid email'],
// password: ['The password must be at least 8 characters']
// }
}
}
まとめ
VineJSは以下のような場面で特におすすめです。
- パフォーマンスが重要なAPI: 高速なバリデーションでレスポンス時間を短縮
- AdonisJSプロジェクト: フレームワークとのシームレスな統合
- 大規模バッチ処理: 大量データの検証を高速に処理
- TypeScript環境: 完全な型安全性
既存のZodやYupからの移行も、同様のAPIデザインにより比較的容易です。次回のプロジェクトでぜひ試してみてください。