laravel/precognitionについて調べてみた
安定してサクサク開発ができる環境が出来てしまうと、それに甘んじてしまい新しい情報のキャッチアップがおろそかになることもあります。
昨今はAIの台頭で便利な世の中にあり、「何か便利なライブラリを教えて」と聞くだけで色々とリストアップしてくれます。
その中でlaravel/precognitionというものが便利そう!と感じたので調べてみました。
目次
laravel/precognitionとは
laravel/precognitionはフロントエンド側で行うバリデーションをLaravelのフォームリクエストを使用して行えるライブラリです。
フォームの入力値の変更やフォーカスが外れたタイミングでコントローラー側の保存処理とajax通信を行い、実際の保存の手前で処理を中断してバリデーションのみ実行する仕組みです。
これまではフロントエンド側とバックエンド側それぞれにバリデーションを定義する必要がありました。バックエンド側に1本化できるので、バリデーションの仕様変更時も1カ所の修正ですみます。
バックエンドの実装
フォームリクエスト
通常通りにFormRequestを定義します。
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class SaveUserRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email'],
];
}
}
ルーティング
ルーティング設定のミドルウェアにprecognitiveを指定します。
Route::post('/users', [UserController::class, 'store'])->middleware('precognitive');
コントローラー
通常通りデータを保存する処理を記述します。プレコグニションリクエスト(検証のみのリクエスト)の場合、Laravelが自動的にこのコントローラーの実行を途中でストップするため、特別な分岐を書く必要はありません。
namespace App\Http\Controllers;
use App\Http\Requests\SaveUserRequest;
use App\Models\User;
class UserController extends Controller
{
public function store(SaveUserRequest $request)
{
User::create($request->validated());
return redirect()->route('users.index')->with('success', 'ユーザー登録が完了しました!');
}
}
フロントエンドの実装
ここではVue3を使用した例で紹介します。
パッケージのインストール
npm install laravel-precognition-vue-inertia
# Reactの場合は laravel-precognition-react-inertia など
Vueコンポーネントの作成
useForm ヘルパーを使用し、入力項目の変更時(またはフォーカス外れ時)に form.validate(‘フィールド名’) を呼び出します。
<script setup>
import { useForm } from 'laravel-precognition-vue-inertia';
// useForm('HTTPメソッド', 'エンドポイントURL', 初期データ)
const form = useForm('post', '/users', {
name: '',
email: '',
});
const submit = () => {
form.submit({
onSuccess: () => form.reset(),
});
};
</script>
<template>
<form @submit.prevent="submit" class="space-y-4 max-w-md mx-auto mt-10">
<!-- 名前フィールド -->
<div>
<label class="block text-sm font-medium">名前</label>
<input
type="text"
v-model="form.name"
@change="form.validate('name')"
class="mt-1 block w-full border rounded-md p-2"
/>
<!-- エラーメッセージの表示 -->
<div v-if="form.invalid('name')" class="text-red-500 text-sm mt-1">
{{ form.errors.name }}
</div>
</div>
<!-- メールアドレスフィールド -->
<div>
<label class="block text-sm font-medium">メールアドレス</label>
<input
type="email"
v-model="form.email"
@change="form.validate('email')"
class="mt-1 block w-full border rounded-md p-2"
/>
<div v-if="form.invalid('email')" class="text-red-500 text-sm mt-1">
{{ form.errors.email }}
</div>
</div>
<!-- 送信ボタン -->
<button
type="submit"
:disabled="form.processing"
class="bg-blue-500 text-white px-4 py-2 rounded-md disabled:opacity-50"
>
登録する
</button>
</form>
</template>
ユーザーが「名前」や「メールアドレス」を入力して別の場所にフォーカスを移した(@change やデフォルトの挙動)タイミングで、バックエンドへ非同期(Ajax)で検証リクエストが飛びます。
エラーがあれば即座に form.errors に格納されて画面に赤字で表示されます。
プレコグニションリクエスト時はデータベースへの保存処理は実行されず、エラーがない状態の「最後の送信ボタン押下」で初めてデータが永続化されます。
メリット・デメリット
メリット
Laravelのフォームリクエストに一元化するため、改修時の手間が減ります。また、フロントエンド側だけでは難しかったDBアクセスを伴う「emailが登録済みかどうか」のチェックも可能になります。
デメリット
通常のフォームと異なり、ajax通信が発生するため、適切な頻度でバリデーションを行うように調整する必要があります。
入力内容の変更時に毎回通信を行うとサーバやネットワークへの負荷が増えるため、フォーカスが外れたタイミングなど最低限のタイミングで行うのがオススメです。
まとめ
個人的にフロントエンドとバックエンドの2重のバリデーションは、ユーザには優しいものの、開発者の立場としては面倒な仕組みだなと考えていました。
しかし今回調べたlaravel/precognitionを利用すればシンプルで簡単にバリデーション機能を実装できることが分かりました。
開発者として今後も新しい機能のキャッチアップを続けて行きたいと思います。



















