VeeValidate4とValibotを使ってNuxt3アプリのバリデーションを実装する

2024/01/06に公開

Vueの最も人気なバリデーションライブラリである VeeValidate の Vue3 系に対応したVeeValidate v4と最近話題の軽量なバリデーションライブラリのValibotを使用してログインフォームのバリデーションを構築していきます。

バージョン等の環境説明

  • Nuxt: 3.9.2 (Vue: 3.4.3)
  • valibot: 0.24.1
  • vee-validate: 4.12.4
  • @vee-validate/valibot: 4.12.4

VeeValidate is なに?

VeeValidate は、Vue でフォームのバリデーションを簡単に行うためのライブラリです。
Valibot 等のバリデーションライブラリと組み合わせて使うことでより柔軟なバリデーションが定義できます。

Valibot is なに?

Valibot はバリデーションライブラリの一種です。類似のライブラリとしてZod, Yup, joiが挙げられます。
Valibot はバンドルサイズがとても軽量なのが特徴です。

Valibot での基本的なスキーマの書き方

schema.ts
import * as v from 'valibot'

const emailSchema = v.string('必須項目です', [
  v.maxLength(255, '255文字以内でご入力ください'),
  v.email('有効なメールアドレスを入力してください'),
])

const passwordSchema = v.string('必須項目です', [
  v.regex(/^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d\W_]{8,32}$/, 'パスワードを正しく入力してください'),
])

export const loginSchema = v.object({
  email: emailSchema,
  password: passwordSchema,
}

👆 上記のようなバリデーションスキーマを構築する手順を順を追って説明していきます。
まず、基本形は下記です。👇

schema.ts
import * as v from 'valibot'

const emailSchema = v.string()

const passwordSchema = v.string()

export const loginSchema = v.object({
  email: emailSchema,
  password: passwordSchema,
})

これでも動きますが、このままだと valibot にデフォルトで設定されている英語のエラーメッセージが出ます。日本向けのアプリを作る場合はエラーメッセージを日本語にしたいので、下記のように変更します。👇

import * as v from "valibot"

const emailSchema = v.string("必須項目です")

const passwordSchema = v.string("必須項目です")

export const loginSchema = v.object({
  email: emailSchema,
  password: passwordSchema,
})

このようにして第一引数にバリデーションに引っかかった場合のメッセージを指定できます。
ただ、もう少し詳細なバリデーションを設定したいので、下記のように変更します。👇

schema.ts
import * as v from 'valibot'

const emailSchema = v.string('必須項目です', [
  v.maxLength(255, '255文字以内でご入力ください'),
  v.email('有効なメールアドレスを入力してください'),
])

const passwordSchema = v.string('必須項目です', [
  v.regex(/^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d\W_]{8,32}$/, 'パスワードを正しく入力してください'),
])

export const loginSchema = v.object({
  email: emailSchema,
  password: passwordSchema,
}

このようにして第二引数に詳細なバリデーションを定義できます。こちらは配列で定義していきます。複数のバリデーションもこの配列に入れることで作っていきます。
今回の場合は、email は 255 文字以内で email の形式(aa@aa.comのような)でのバリデーションです。
パスワードに関しては、regexという API が使われていますが、これは正規表現を定義できます。この正規表現は「この正規表現は少なくとも 1 つの小文字、1 つの大文字、1 つの数字を含み、全体の長さが 8 文字以上 32 文字以下のパスワード」という意味です。

maxLength, email, regex以外にも様々な API があります。他にも知りたい方はvalibot 公式の API リファレンスを参照してください。

VeeValidate と組み合わせて使う方法

@vee-validate/valibotから import される toTypedSchemaを使用します。これにより、フォームの値と送信された値は自動的に型付けされ、そのスキーマの入力と出力の両方の型に対応します。
実装方法としては簡単で、先程作った schema を toTypedSchemaの引数として渡すだけです。

schema.ts
import * as v from 'valibot'
import { toTypedSchema } from '@vee-validate/valibot'

const emailSchema = v.string('必須項目です', [
  v.maxLength(255, '255文字以内でご入力ください'),
  v.email('有効なメールアドレスを入力してください'),
])

const passwordSchema = v.string('必須項目です', [
  v.regex(/^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d\W_]{8,32}$/, 'パスワードを正しく入力してください'),
])

export const loginFormSchema = toTypedSchema(
  v.object({
    email: emailSchema,
    password: passwordSchema,
  }),
)

これで vue 側で使用する準備が整いました。
実装する vue は下記のようになります。👇

Login.vue
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { loginFormSchema } from '~/schema' // 作成したschemaのimport

// 先程作ったschemaをuseFormのvalidationSchemaオプションに渡す
const { handleSubmit } = useForm({
  validationSchema: loginFormSchema,
})

const login = handleSubmit((values) => {
  console.log(values.email); //入力されたemail
  console.log(values.password); //入力されたpassword
})
</script>

<template>
  <form @submit="login">
    <InputText name="email" type="email" label-text="メールアドレス" />
    <InputText name="password" type="password" label-text="パスワード" />
    <button>ログイン</button>
  </form>
</template>
InputText.vue
<script setup lang="ts">
import { useField } from 'vee-validate'

const props = defineProps<{
  name: string
  type?: string
  labelText?: string
}>()

const { value, errorMessage } = useField(() => props.name)
</script>

<template>
  <label>
    {{ labelText }}
    <input v-model="value" :type="type">
    <span>{{ errorMessage }}</span>
  </label>
</template>

これで実際にバリデーションがかかるログインフォームを構築することができます。

Valibot のスキーマから型を生成する方法

先程の実装には直接は関係ないのですが、Valibot のスキーマから型を生成することができます。props 等で型を定義しなければいけない場面ではよく使うので覚えておきましょう。
Outputという API を使用します。

schema.ts
import * as v from 'valibot'

const emailSchema = v.string('必須項目です', [
  v.maxLength(255, '255文字以内でご入力ください'),
  v.email('有効なメールアドレスを入力してください'),
])

const passwordSchema = v.string('必須項目です', [
  v.regex(/^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d\W_]{8,32}$/, 'パスワードを正しく入力してください'),
])

export const loginFormSchema = v.object({
  email: emailSchema,
  password: passwordSchema,
})

// Valibotのスキーマから型を生成
export type LoginFormSchema = v.Output<typeof loginFormSchema>

// 出力される型
// type LoginFormSchema = {
//   email: string;
//   password: string;
// }

vee-validate 側の API の toTypedSchemaでラップしているとエラーになるので注意が必要です。

export const loginFormSchema = toTypedSchema(v.object({
  email: emailSchema,
  password: passwordSchema,
}))

// 🙅‍♂エラーになる
export type LoginFormSchema = v.Output<typeof loginFormSchema>
const loginFormSchemaRaw = v.object({
  email: emailSchema,
  password: passwordSchema,
})
export const loginFormSchema = toTypedSchema(loginFormSchemaRaw)
// 🙆‍♂️エラーにならない
export type LoginFormSchema = v.Output<typeof loginFormSchemaRaw>

toTypedSchemaでラップしていない方を loginFormSchemaRawと命名して実際にフォームで使用する方は loginFormSchemaで使用できるように工夫しました。※もっと良い命名があるかもですが、一旦これで落ち着いてます。

まとめ

この記事では、VeeValidate と Valibot を使用してログインフォームのバリデーションを構築する方法を紹介しました。

VeeValidate は、Vue でフォームのバリデーションを簡単に行うためのライブラリです。
Valibot は、バリデーションライブラリの一種で、バンドルサイズがとても軽量なのが特徴です。

この 2 つのライブラリを組み合わせることで、軽量で柔軟なフォームのバリデーションを構築することができます。

簡単に手順をおさらいするとこのようになります。

  1. Valibot を使用して、フォームのバリデーションルールを定義する
  2. @vee-validate/valibot から import される toTypedSchema を使用して、スキーマを型付けする
  3. useForm の validationSchema オプションに、型付けしたスキーマを渡す

この手順を参考に、ぜひご自身のプロジェクトでフォームのバリデーションを構築してみてください。
また、間違っている点があったらコメントにて教えていただけると幸いです。

GitHubで編集を提案

Discussion