Trải nghiệm Frontend "mượt" với Laravel Precognition

· 5 min read

Một trong những nỗi đau ("pain points") lớn nhất khi phát triển ứng dụng Full-stack là sự trùng lặp logic xác thực (validation logic).

Bạn viết rules validation trong Form Request của Laravel để bảo vệ backend. Nhưng để UX tốt (người dùng biết lỗi ngay khi gõ), bạn lại phải viết lại các rules đó bằng JavaScript ở frontend (sử dụng VeeValidate, Zod, hay Yup...).

Điều này dẫn đến:

  1. Code duplication: Một quy tắc đổi, phải sửa 2 nơi.
  2. Inconsistency: Regex email của PHP có thể khác một chút với JS.
  3. Security risks: Nếu lỡ quên update backend sau khi sửa frontend.

Laravel Precognition ra đời để giải quyết vấn đề này. Nó cho phép frontend "hỏi" backend: "Nếu tôi submit dữ liệu này thì có hợp lệ không?" mà không thực sự thực thi controller.

Precognition hoạt động như thế nào?

Về cơ bản, Precognition chặn request bằng một middleware đặc biệt.

  1. Frontend gửi request (ví dụ: POST /users) kèm header Precognition: true.
  2. Laravel middleware phát hiện header này.
  3. Laravel chạy qua quá trình Validation (Form Request).
  4. nếu Validation Fail -> Trả về lỗi 422 như bình thường.
  5. Nếu Validation Pass -> Dừng lại ngay, không chạy vào Controller, trả về 204 No Content.

Điều này cực kỳ nhanh và nhẹ, vì nó bỏ qua toàn bộ logic xử lý nặng nề trong Controller (DB insert, gửi mail, queue job...).

Cài đặt và Sử dụng

1. Chuẩn bị phía Backend

Trong Laravel 10+, Precognition đã được tích hợp sẵn. Bạn chỉ cần đảm bảo middleware HandlePrecognitiveRequests được đăng ký (thường là mặc định trong app/Http/Kernel.php hoặc bootstrap/app.php bản mới).

Giả sử bạn có một UserStoreRequest:

// app/Http/Requests/UserStoreRequest.php
public function rules(): array
{
    return [
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'email', 'unique:users,email'],
        'password' => ['required', 'min:8', 'confirmed'],
    ];
}

Controller của bạn không cần thay đổi gì cả:

public function store(UserStoreRequest $request) 
{
    // Logic này sẽ KHÔNG chạy khi request là precognitive
    User::create($request->validated());
}

2. Tích hợp phía Frontend (Vue 3 Example)

Laravel cung cấp library cho các framework phổ biến.

npm install laravel-precognition-vue

Sử dụng useForm của Precognition thay vì Inertia hay ref thường:

<script setup>
import { useForm } from 'laravel-precognition-vue';

const form = useForm('post', '/users', {
    name: '',
    email: '',
    password: '',
    password_confirmation: '',
});

const submit = () => form.submit({
    preserveScroll: true,
    onSuccess: () => form.reset(),
});
</script>

<template>
    <form @submit.prevent="submit">
        <div>
            <label>Name</label>
            <!-- validate('name') sẽ gọi API kiểm tra ngay khi blur hoặc change -->
            <input 
                v-model="form.name" 
                @change="form.validate('name')"
            />
            <div v-if="form.invalid('name')" class="error">
                {{ form.errors.name }}
            </div>
        </div>

        <!-- Tương tự cho Email, Password... -->
        
        <button :disabled="form.processing">Create User</button>
    </form>
</template>

3. Tùy chỉnh quy tắc khi Precognition chạy

Đôi khi bạn có những rule "nặng" (ví dụ check unique trong database scan bảng lớn) mà bạn không muốn chạy mỗi lần user gõ phím.

Bạn có thể dùng phương thức isPrecognitive() của Request để điều chỉnh:

public function rules(): array
{
    return [
        'avatar' => [
            ...
            // Chỉ validate dimension ảnh khi submit thật
            !$this->isPrecognitive() ? Rule::dimensions()->maxWidth(1000) : null, 
        ],
        // ...
    ];
}

Side Effects (Cẩn thận!)

Vì Precognition chạy Validation, nên nếu bạn để logic "side effect" (như tạo file, log activity) trong phương thức prepareForValidation hoặc các Custom Rule, chúng có thể bị chạy nhiều lần.

Quy tắc vàng: Validation chỉ nên là Validation. Không thực hiện thay đổi trạng thái hệ thống trong lớp Validation.

Kết luận

Laravel Precognition là cầu nối tuyệt vời giữa UX mượt mà của Client-side validation và sự chắc chắn, bảo mật của Server-side validation. Nó loại bỏ hoàn toàn việc duplicate logic, giúp code base của bạn DRY (Don't Repeat Yourself) hơn bao giờ hết.

Nếu đang làm dự án Inertia.js hoặc SPA với Laravel API, đây là tính năng "must-have".

Bình luận