Проблема: щоб показувати помилки під полем одразу при введенні, правила валідації часто дублюють на фронтенді (Zod, Yup, VeeValidate). Тепер є два набори правил, які розходяться: unique:users,email на фронтенді взагалі не перевірити.
Precognition дозволяє фронтенду «запитати» сервер: «чи пройшли б ці дані валідацію?» - без виконання самої дії.
Як це працює:
- фронтенд надсилає запит на той самий маршрут зі спеціальним заголовком
Precognition: true; - middleware
HandlePrecognitiveRequestsзапускає лише middleware маршруту й валідацію (Form Request), але не викликає контролер; - відповідь -
204(усе гаразд) або422з помилками; - фронтенд показує помилки під полями.
Бекенд:
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
Route::post('/users', [UserController::class, 'store'])
->middleware([HandlePrecognitiveRequests::class]);
Правила лишаються в одному місці - у StoreUserRequest.
Фронтенд (Vue, React чи Alpine):
<script setup>
import { useForm } from 'laravel-precognition-vue';
const form = useForm('post', '/users', { name: '', email: '' });
</script>
<template>
<input v-model="form.email" @change="form.validate('email')" />
<div v-if="form.invalid('email')">{{ form.errors.email }}</div>
<button :disabled="form.processing" @click="form.submit()">Зберегти</button>
</template>
validate('email') перевіряє лише це поле - помилки інших, ще не заповнених полів не показуються.
На що зважати:
- побічні ефекти в middleware: прекогнітивний запит проходить через middleware маршруту. Middleware, що рахує взаємодії чи пише аудит, має пропускати такі запити:
$request->isPrecognitive(); - авторизація в
authorize()Form Request теж виконується - це правильно, але враховуйте вартість; - навантаження: кожна зміна поля - запит до сервера. Для дорогих правил (зовнішні API) варто подумати, чи потрібна жива перевірка;
- файли: за замовчуванням файли під час прекогнітивної валідації не надсилаються, щоб не завантажувати їх повторно.
Inertia 2.3+ має вбудовану підтримку Precognition у формах, тож окремий пакет там не потрібен.