Laravel Precognition使ってみた 〜ハマりポイントを添えて〜
こんにちは、さわちゃんです。
先日とある案件でLaravel Precognitionを使用してみましたが、個人的にとても良いなと思ったので今回ご紹介していきます。
リアルタイムバリデーションの定義としては、submit処理を行わずともバリデーションチェックを行い、入力異常などを検知・表示することを指しています。
このライブラリについてざっくりと説明すると、バリデーションチェックをバックエンド側(Laravel側)に任せ、Laravelで書いたフォームリクエストのルールでバリデーションチェックを行うようにしてくれます。
バリデーションチェックの際、バックエンド側にリクエストを送信することになりますが、このときミドルウェアからフォームリクエストのバリデーションまでを行い、それ以降のコントローラの処理は行われません。
より詳しい説明や導入方法は公式ドキュメントを参照ください。
https://readouble.com/laravel/10.x/ja/precognition.html
よくあるのがフロントエンド側ではYupやZodを利用して独自のルールを記述し、リアルタイムバリデーションを実現する形ですが、純粋にフロントエンドとバックエンドでそれぞれルールを書くことになってしまい二度手間ですし、DBアクセスを伴うチェックなどはフロントで実現するのは大変ですよね。
また、フロントエンドとバックエンドで別々のルールを使用することになるため、ルールの不整合が起きてしまう可能性もあります。
Laravel Precognitionを用いればバックエンド側にルールをすべて任せることになるので、上記の問題が解決します。
先日私が担当した案件では複雑なバリデーションルールがあり、フロントエンドでは到底ルールの実現が難しかったのですが、本ライブラリを使用することでかなり細かいチェックを行うことができ、かつ、実装工数も大幅に削減できました。
例えば、テキストフィールドで何か文字を打つたびにバリデーションチェックを行いたいという場合、文字を1つ打つごとに1リクエスト送信されてしまうので、通信コストがかかってしまいます。
基本的には文字を打つたびではなく、フォーカスが離れたとき(blur時)にバリデーションチェックを行う使い方になるかなと思います。
またフロントエンドだけで完結しないので、通信環境によってはバリデーションチェック〜異常検知〜異常表示までに若干のディレイが発生してしまうことがあります。
利用ユーザーが多く、また入力項目も多いシステムなどでは向いていないかなと個人的には感じています。
inputのnameを
このあたり、Laravel Precognitionがよしなにやってくれるので使っていて気にすることはあまりないのですが、もしこのHTTPリクエストヘッダを強引に消した場合、全パラメータのバリデーションチェックを一括で行う挙動になります。
useFormのconfigにはtransformRequestを設定することができ、リクエストを行う直前にリクエストパラメータに手を加えることが可能です。
ここでハマりポイントなのですが、useFormを宣言する際に指定したconfigのtransformRequestはバリデーションチェック用のリクエストにしか適用されません。
なので、useFormが提供しているsubmitメソッドを用いて実際にリクエストを送信する場合にはtransformRequestの処理は適用されず、予期せぬ不具合が発生することがあります。
バリデーションチェックではない本当のsubmit時にもtransformRequestを適用させたい場合は、submitメソッドに指定できるconfigのtransformRequestを利用する必要があります。
弊社が最近よく採用しているInertia.jsとの相性もいいですし、SPA(Next.js)でも導入しましたが大きなトラブルもなく利用することができました。
ぜひ皆さんも利用してみてください〜
先日とある案件でLaravel Precognitionを使用してみましたが、個人的にとても良いなと思ったので今回ご紹介していきます。
本記事で使用するライブラリのバージョン
"laravel-precognition": "0.4.1"
https://github.com/laravel/precognition
Laravel Precognition
Laravel 9系から利用可能になったリアルタイムバリデーションを行うライブラリです。リアルタイムバリデーションの定義としては、submit処理を行わずともバリデーションチェックを行い、入力異常などを検知・表示することを指しています。
このライブラリについてざっくりと説明すると、バリデーションチェックをバックエンド側(Laravel側)に任せ、Laravelで書いたフォームリクエストのルールでバリデーションチェックを行うようにしてくれます。
バリデーションチェックの際、バックエンド側にリクエストを送信することになりますが、このときミドルウェアからフォームリクエストのバリデーションまでを行い、それ以降のコントローラの処理は行われません。
より詳しい説明や導入方法は公式ドキュメントを参照ください。
https://readouble.com/laravel/10.x/ja/precognition.html
メリット
なんといってもバリデーションルールをバックエンド側だけで統一できることが最大のメリットかなと思ってます。よくあるのがフロントエンド側ではYupやZodを利用して独自のルールを記述し、リアルタイムバリデーションを実現する形ですが、純粋にフロントエンドとバックエンドでそれぞれルールを書くことになってしまい二度手間ですし、DBアクセスを伴うチェックなどはフロントで実現するのは大変ですよね。
また、フロントエンドとバックエンドで別々のルールを使用することになるため、ルールの不整合が起きてしまう可能性もあります。
Laravel Precognitionを用いればバックエンド側にルールをすべて任せることになるので、上記の問題が解決します。
先日私が担当した案件では複雑なバリデーションルールがあり、フロントエンドでは到底ルールの実現が難しかったのですが、本ライブラリを使用することでかなり細かいチェックを行うことができ、かつ、実装工数も大幅に削減できました。
デメリット
大きなデメリットとしては、バリデーションチェックを行うたびにバックエンド側へ通信が発生することです。例えば、テキストフィールドで何か文字を打つたびにバリデーションチェックを行いたいという場合、文字を1つ打つごとに1リクエスト送信されてしまうので、通信コストがかかってしまいます。
基本的には文字を打つたびではなく、フォーカスが離れたとき(blur時)にバリデーションチェックを行う使い方になるかなと思います。
またフロントエンドだけで完結しないので、通信環境によってはバリデーションチェック〜異常検知〜異常表示までに若干のディレイが発生してしまうことがあります。
利用ユーザーが多く、また入力項目も多いシステムなどでは向いていないかなと個人的には感じています。
【小ネタ】複数inputがある場合に一つだけバリデーションチェックを行う仕組み
バリデーションチェックの際のリクエストにおいて、
Precognition-Validate-Only
というHTTPリクエストヘッダがつきます。inputのnameを
"Precognition-Validate-Only": "title"
のような形で指定することによってそのパラメータのみをチェックできる仕組みです。このあたり、Laravel Precognitionがよしなにやってくれるので使っていて気にすることはあまりないのですが、もしこのHTTPリクエストヘッダを強引に消した場合、全パラメータのバリデーションチェックを一括で行う挙動になります。
ハマりポイント(transformRequest)
まず前提として、Laravel Precognitionでは基本的にフロントエンドで使用するフレームワーク(React, Vueなど)に対してそれぞれ最適なライブラリを用意してくれていて、そのライブラリが提供しているuseFormのフォームヘルパを使用することになります。useFormのconfigにはtransformRequestを設定することができ、リクエストを行う直前にリクエストパラメータに手を加えることが可能です。
ここでハマりポイントなのですが、useFormを宣言する際に指定したconfigのtransformRequestはバリデーションチェック用のリクエストにしか適用されません。
なので、useFormが提供しているsubmitメソッドを用いて実際にリクエストを送信する場合にはtransformRequestの処理は適用されず、予期せぬ不具合が発生することがあります。
バリデーションチェックではない本当のsubmit時にもtransformRequestを適用させたい場合は、submitメソッドに指定できるconfigのtransformRequestを利用する必要があります。
import { useForm } from "laravel-precognition-react-inertia";
const { submit } = useForm(
'post',
'/blogs/create',
{
title: 'こんにちは、さわちゃんです',
content: '技術ブログです'
},
{
transformRequest: (data) => {
// バリデーションチェック用のリクエストでのみ処理が行われる
}
}
)
const handleSubmit = () => {
submit(
{
transformRequest: (data) => {
// submit用のリクエストでのみ処理が行われる
}
)
)
}
おわりに
Laravel Precognitionについてざっくり説明してきました。弊社が最近よく採用しているInertia.jsとの相性もいいですし、SPA(Next.js)でも導入しましたが大きなトラブルもなく利用することができました。
ぜひ皆さんも利用してみてください〜
- PHP , Laravel , Javascript , vue.js , Inertia.js , React