Precognition
번역일: 2026년 6월 20일
Precognition
소개
Laravel Precognition은 아직 실행되지 않은 HTTP 요청의 결과를 미리 예측할 수 있게 해주는 기능입니다. 가장 대표적인 활용 사례는 프론트엔드 JavaScript 애플리케이션에서 실시간 유효성 검사를 제공하는 것입니다. 백엔드의 유효성 검사 규칙을 프론트엔드에 중복 작성할 필요 없이, 서버의 규칙을 그대로 활용할 수 있습니다.
Laravel이 "precognitive 요청"을 수신하면 해당 라우트의 모든 미들웨어를 실행하고, 폼 리퀘스트 유효성 검사를 포함한 컨트롤러의 의존성을 해석하지만, 컨트롤러 메서드 자체는 실행하지 않습니다.
NOTE
Inertia 2.3부터는 Precognition 지원이 내장되어 있습니다. 자세한 내용은 Inertia Forms 문서를 참고하세요. Inertia 이전 버전에서는 Precognition 0.x를 사용해야 합니다.
실시간 유효성 검사
Vue 사용
Laravel Precognition을 사용하면 Vue 프론트엔드에 유효성 검사 규칙을 중복 작성하지 않고도 사용자에게 실시간 유효성 검사 경험을 제공할 수 있습니다. 사용자 생성 폼을 예제로 살펴보겠습니다.
먼저 라우트에 Precognition을 활성화하려면 HandlePrecognitiveRequests 미들웨어를 라우트 정의에 추가해야 합니다. 또한 해당 라우트의 유효성 검사 규칙을 담을 폼 리퀘스트를 생성해야 합니다.
use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
Route::post('/users', function (StoreUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);다음으로 NPM을 통해 Vue용 Laravel Precognition 프론트엔드 헬퍼를 설치합니다.
npm install laravel-precognition-vue패키지를 설치했으면 Precognition의 useForm 함수를 사용해 폼 객체를 생성합니다. HTTP 메서드(post), 대상 URL(/users), 초기 폼 데이터를 인자로 전달합니다.
실시간 유효성 검사를 활성화하려면 각 입력 필드의 change 이벤트에서 폼의 validate 메서드를 호출하고, 해당 입력 필드의 이름을 전달합니다.
<script setup>
import { useForm } from 'laravel-precognition-vue';
const form = useForm('post', '/users', {
name: '',
email: '',
});
const submit = () => form.submit();
</script>
<template>
<form @submit.prevent="submit">
<label for="name">이름</label>
<input
id="name"
v-model="form.name"
@change="form.validate('name')"
/>
<div v-if="form.invalid('name')">
{{ form.errors.name }}
</div>
<label for="email">이메일</label>
<input
id="email"
type="email"
v-model="form.email"
@change="form.validate('email')"
/>
<div v-if="form.invalid('email')">
{{ form.errors.email }}
</div>
<button :disabled="form.processing">
사용자 생성
</button>
</form>
</template>사용자가 폼을 작성하면 Precognition이 라우트의 폼 리퀘스트에 정의된 유효성 검사 규칙을 기반으로 실시간 유효성 검사 결과를 제공합니다. 입력값이 변경될 때마다 디바운스(debounce)된 "precognitive" 유효성 검사 요청이 Laravel 애플리케이션으로 전송됩니다. 폼의 setValidationTimeout 함수를 호출해 디바운스 대기 시간을 조정할 수 있습니다.
form.setValidationTimeout(3000);유효성 검사 요청이 진행 중일 때 폼의 validating 속성은 true가 됩니다.
<div v-if="form.validating">
검사 중...
</div>유효성 검사 요청이나 폼 제출 중에 반환된 유효성 검사 오류는 자동으로 폼의 errors 객체에 채워집니다.
<div v-if="form.invalid('email')">
{{ form.errors.email }}
</div>폼에 오류가 있는지는 hasErrors 속성으로 확인할 수 있습니다.
<div v-if="form.hasErrors">
<!-- ... -->
</div>입력 필드의 이름을 valid 또는 invalid 함수에 전달하면 해당 필드의 유효성 검사 통과 여부를 확인할 수 있습니다.
<span v-if="form.valid('email')">
✅
</span>
<span v-else-if="form.invalid('email')">
❌
</span>WARNING
입력 필드는 값이 변경되고 유효성 검사 응답을 받은 이후에만 유효(valid) 또는 유효하지 않음(invalid) 상태로 표시됩니다.
Precognition으로 폼의 일부 입력 필드만 검사하는 경우, 오류를 수동으로 초기화하는 것이 유용할 수 있습니다. 폼의 forgetError 함수를 사용하면 됩니다.
<input
id="avatar"
type="file"
@change="(e) => {
form.avatar = e.target.files[0]
form.forgetError('avatar')
}"
>사용자가 직접 상호작용한 입력 필드는 change 이벤트로 검사할 수 있지만, 사용자가 아직 건드리지 않은 필드를 검사해야 하는 경우도 있습니다. 멀티 스텝 "위저드(wizard)" 폼을 구성할 때 다음 단계로 넘어가기 전에 현재 화면의 모든 입력 필드를 검사하고 싶은 상황이 대표적인 예입니다.
이 경우 validate 메서드를 호출할 때 only 옵션에 검사할 필드명 배열을 전달합니다. onSuccess 또는 onValidationError 콜백으로 결과를 처리할 수 있습니다.
<button
type="button"
@click="form.validate({
only: ['name', 'email', 'phone'],
onSuccess: (response) => nextStep(),
onValidationError: (response) => /* ... */,
})"
>다음 단계</button>폼 제출 응답에 반응하는 코드도 실행할 수 있습니다. 폼의 submit 함수는 Axios 요청 프로미스(promise)를 반환하므로, 제출 성공 시 폼을 초기화하거나 실패 시 오류를 처리하는 등의 작업을 편리하게 수행할 수 있습니다.
const submit = () => form.submit()
.then(response => {
form.reset();
alert('사용자가 생성되었습니다.');
})
.catch(error => {
alert('오류가 발생했습니다.');
});폼 제출 요청이 진행 중인지는 processing 속성으로 확인할 수 있습니다.
<button :disabled="form.processing">
제출
</button>React 사용
Laravel Precognition을 사용하면 React 프론트엔드에도 유효성 검사 규칙을 중복 작성하지 않고 실시간 유효성 검사를 제공할 수 있습니다. 사용자 생성 폼을 예제로 살펴보겠습니다.
먼저 라우트에 Precognition을 활성화하려면 HandlePrecognitiveRequests 미들웨어를 라우트 정의에 추가하고, 유효성 검사 규칙을 담을 폼 리퀘스트를 생성합니다.
use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
Route::post('/users', function (StoreUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);다음으로 NPM을 통해 React용 Laravel Precognition 프론트엔드 헬퍼를 설치합니다.
npm install laravel-precognition-react패키지를 설치했으면 Precognition의 useForm 함수로 폼 객체를 생성합니다. 실시간 유효성 검사를 활성화하려면 각 입력 필드의 change 이벤트와 blur 이벤트를 모두 처리해야 합니다. change 이벤트 핸들러에서는 setData 함수로 폼 데이터를 갱신하고, blur 이벤트 핸들러에서는 validate 메서드를 호출합니다.
import { useForm } from 'laravel-precognition-react';
export default function Form() {
const form = useForm('post', '/users', {
name: '',
email: '',
});
const submit = (e) => {
e.preventDefault();
form.submit();
};
return (
<form onSubmit={submit}>
<label htmlFor="name">이름</label>
<input
id="name"
value={form.data.name}
onChange={(e) => form.setData('name', e.target.value)}
onBlur={() => form.validate('name')}
/>
{form.invalid('name') && <div>{form.errors.name}</div>}
<label htmlFor="email">이메일</label>
<input
id="email"
value={form.data.email}
onChange={(e) => form.setData('email', e.target.value)}
onBlur={() => form.validate('email')}
/>
{form.invalid('email') && <div>{form.errors.email}</div>}
<button disabled={form.processing}>
사용자 생성
</button>
</form>
);
};사용자가 폼을 작성하면 Precognition이 라우트의 폼 리퀘스트에 정의된 규칙을 기반으로 실시간 유효성 검사 결과를 제공합니다. setValidationTimeout 함수로 디바운스 대기 시간을 조정할 수 있습니다.
form.setValidationTimeout(3000);유효성 검사 요청이 진행 중일 때 폼의 validating 속성은 true가 됩니다.
{form.validating && <div>검사 중...</div>}유효성 검사 오류는 자동으로 폼의 errors 객체에 채워집니다.
{form.invalid('email') && <div>{form.errors.email}</div>}폼에 오류가 있는지는 hasErrors 속성으로 확인합니다.
{form.hasErrors && <div><!-- ... --></div>}입력 필드의 유효성 검사 통과 여부는 valid와 invalid 함수로 확인합니다.
{form.valid('email') && <span>✅</span>}
{form.invalid('email') && <span>❌</span>}WARNING
입력 필드는 값이 변경되고 유효성 검사 응답을 받은 이후에만 유효(valid) 또는 유효하지 않음(invalid) 상태로 표시됩니다.
특정 필드의 오류를 수동으로 초기화하려면 forgetError 함수를 사용합니다.
<input
id="avatar"
type="file"
onChange={(e) => {
form.setData('avatar', e.target.files[0]);
form.forgetError('avatar');
}}
>멀티 스텝 위저드처럼 사용자가 아직 상호작용하지 않은 필드를 포함해 검사해야 할 때는 validate 메서드에 only 옵션을 전달합니다.
<button
type="button"
onClick={() => form.validate({
only: ['name', 'email', 'phone'],
onSuccess: (response) => nextStep(),
onValidationError: (response) => /* ... */,
})}
>다음 단계</button>폼의 submit 함수는 Axios 요청 프로미스를 반환하므로 제출 결과에 따른 처리를 연결할 수 있습니다.
const submit = (e) => {
e.preventDefault();
form.submit()
.then(response => {
form.reset();
alert('사용자가 생성되었습니다.');
})
.catch(error => {
alert('오류가 발생했습니다.');
});
};폼 제출 요청이 진행 중인지는 processing 속성으로 확인합니다.
<button disabled={form.processing}>
제출
</button>Alpine과 Blade 사용
Laravel Precognition을 사용하면 Alpine.js와 Blade 조합에서도 유효성 검사 규칙 중복 없이 실시간 유효성 검사를 제공할 수 있습니다. 사용자 생성 폼을 예제로 살펴보겠습니다.
먼저 HandlePrecognitiveRequests 미들웨어를 라우트 정의에 추가하고, 폼 리퀘스트를 생성합니다.
use App\Http\Requests\CreateUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
Route::post('/users', function (CreateUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);다음으로 NPM을 통해 Alpine용 Laravel Precognition 프론트엔드 헬퍼를 설치합니다.
npm install laravel-precognition-alpine설치 후 resources/js/app.js 파일에서 Alpine에 Precognition 플러그인을 등록합니다.
import Alpine from 'alpinejs';
import Precognition from 'laravel-precognition-alpine';
window.Alpine = Alpine;
Alpine.plugin(Precognition);
Alpine.start();플러그인을 등록하면 Precognition의 $form 매직을 사용해 폼 객체를 생성할 수 있습니다. 각 입력 필드의 change 이벤트에서 validate 메서드를 호출해 실시간 유효성 검사를 활성화합니다.
<form x-data="{
form: $form('post', '/register', {
name: '',
email: '',
}),
}">
@csrf
<label for="name">이름</label>
<input
id="name"
name="name"
x-model="form.name"
@change="form.validate('name')"
/>
<template x-if="form.invalid('name')">
<div x-text="form.errors.name"></div>
</template>
<label for="email">이메일</label>
<input
id="email"
name="email"
x-model="form.email"
@change="form.validate('email')"
/>
<template x-if="form.invalid('email')">
<div x-text="form.errors.email"></div>
</template>
<button :disabled="form.processing">
사용자 생성
</button>
</form>사용자가 폼을 작성하면 라우트의 폼 리퀘스트에 정의된 규칙을 기반으로 실시간 유효성 검사 결과가 제공됩니다. setValidationTimeout 함수로 디바운스 대기 시간을 조정할 수 있습니다.
form.setValidationTimeout(3000);유효성 검사 요청이 진행 중일 때 폼의 validating 속성은 true가 됩니다.
<template x-if="form.validating">
<div>검사 중...</div>
</template>유효성 검사 오류는 자동으로 폼의 errors 객체에 채워집니다.
<template x-if="form.invalid('email')">
<div x-text="form.errors.email"></div>
</template>폼에 오류가 있는지는 hasErrors 속성으로 확인합니다.
<template x-if="form.hasErrors">
<div><!-- ... --></div>
</template>입력 필드의 유효성 검사 통과 여부는 valid와 invalid 함수로 확인합니다.
<template x-if="form.valid('email')">
<span>✅</span>
</template>
<template x-if="form.invalid('email')">
<span>❌</span>
</template>WARNING
입력 필드는 값이 변경되고 유효성 검사 응답을 받은 이후에만 유효(valid) 또는 유효하지 않음(invalid) 상태로 표시됩니다.
멀티 스텝 위저드처럼 사용자가 아직 상호작용하지 않은 필드를 포함해 검사해야 할 때는 validate 메서드에 only 옵션을 전달합니다.
<button
type="button"
@click="form.validate({
only: ['name', 'email', 'phone'],
onSuccess: (response) => nextStep(),
onValidationError: (response) => /* ... */,
})"
>다음 단계</button>폼 제출 요청이 진행 중인지는 processing 속성으로 확인합니다.
<button :disabled="form.processing">
제출
</button>이전 폼 데이터 복원
위 예제에서는 Precognition으로 실시간 유효성 검사를 수행하면서 폼 제출 자체는 전통적인 서버 사이드 방식으로 처리합니다. 이 경우 서버 사이드 폼 제출에서 반환된 "이전 입력값"과 유효성 검사 오류를 폼에 다시 채워야 합니다.
<form x-data="{
form: $form('post', '/register', {
name: '{{ old('name') }}',
email: '{{ old('email') }}',
}).setErrors({{ Js::from($errors->messages()) }}),
}">XHR로 폼을 제출하고 싶다면 폼의 submit 함수를 사용할 수 있습니다. 이 함수는 Axios 요청 프로미스를 반환합니다.
<form
x-data="{
form: $form('post', '/register', {
name: '',
email: '',
}),
submit() {
this.form.submit()
.then(response => {
this.form.reset();
alert('사용자가 생성되었습니다.')
})
.catch(error => {
alert('오류가 발생했습니다.');
});
},
}"
@submit.prevent="submit"
>Axios 설정
Precognition 유효성 검사 라이브러리는 백엔드에 요청을 보낼 때 Axios HTTP 클라이언트를 사용합니다. 필요한 경우 Axios 인스턴스를 커스터마이징할 수 있습니다. 예를 들어 laravel-precognition-vue 라이브러리를 사용할 때 resources/js/app.js 파일에서 모든 요청에 공통 헤더를 추가할 수 있습니다.
import { client } from 'laravel-precognition-vue';
client.axios().defaults.headers.common['Authorization'] = authToken;또는 이미 설정된 Axios 인스턴스가 있다면 해당 인스턴스를 Precognition이 사용하도록 지정할 수 있습니다.
import Axios from 'axios';
import { client } from 'laravel-precognition-vue';
window.axios = Axios.create()
window.axios.defaults.headers.common['Authorization'] = authToken;
client.use(window.axios)배열 유효성 검사
배열이나 중첩 객체 내의 필드를 검사할 때는 와일드카드(*)를 사용할 수 있습니다. *는 경로의 단일 세그먼트 하나와 매칭됩니다.
// 배열에 있는 모든 사용자의 email 필드를 검사
form.validate('users.*.email');
// profile 객체의 모든 필드를 검사
form.validate('profile.*');
// 모든 사용자의 모든 필드를 검사
form.validate('users.*.*');유효성 검사 규칙 커스터마이징
요청의 isPrecognitive 메서드를 사용하면 precognitive 요청 시 실행되는 유효성 검사 규칙을 커스터마이징할 수 있습니다.
예를 들어, 사용자 생성 폼에서 비밀번호가 "유출된 적 없는 안전한 비밀번호"인지 검사하는 규칙은 최종 폼 제출 시에만 적용하고, 실시간 유효성 검사 시에는 필수 입력 여부와 최소 길이만 확인하고 싶을 수 있습니다. isPrecognitive 메서드를 사용해 폼 리퀘스트의 규칙을 다음과 같이 분기할 수 있습니다.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;
class StoreUserRequest extends FormRequest
{
/**
* 요청에 적용할 유효성 검사 규칙을 반환합니다.
*
* @return array
*/
protected function rules()
{
return [
'password' => [
'required',
$this->isPrecognitive()
? Password::min(8)
: Password::min(8)->uncompromised(),
],
// ...
];
}
}파일 업로드 처리
기본적으로 Laravel Precognition은 precognitive 유효성 검사 요청 시 파일을 업로드하거나 검사하지 않습니다. 이는 대용량 파일이 불필요하게 여러 번 업로드되는 것을 방지하기 위함입니다.
이 동작 때문에 해당 필드가 최종 폼 제출 시에만 필수(required)임을 명시하도록 유효성 검사 규칙을 커스터마이징해야 합니다.
/**
* 요청에 적용할 유효성 검사 규칙을 반환합니다.
*
* @return array
*/
protected function rules()
{
return [
'avatar' => [
...$this->isPrecognitive() ? [] : ['required'],
'image',
'mimes:jpg,png',
'dimensions:ratio=3/2',
],
// ...
];
}모든 유효성 검사 요청에 파일을 포함시키고 싶다면 클라이언트 측 폼 인스턴스에서 validateFiles 함수를 호출합니다.
form.validateFiles();사이드 이펙트 관리
HandlePrecognitiveRequests 미들웨어를 라우트에 추가할 때는 다른 미들웨어에 precognitive 요청 시 건너뛰어야 할 사이드 이펙트가 있는지 검토해야 합니다.
예를 들어, 각 사용자의 애플리케이션 "상호작용" 횟수를 증가시키는 미들웨어가 있다면, precognitive 요청은 실제 상호작용으로 집계되지 않도록 처리하고 싶을 것입니다. 이 경우 요청의 isPrecognitive 메서드를 확인한 후 카운트를 증가시키도록 구현합니다.
<?php
namespace App\Http\Middleware;
use App\Facades\Interaction;
use Closure;
use Illuminate\Http\Request;
class InteractionMiddleware
{
/**
* 들어오는 요청을 처리합니다.
*/
public function handle(Request