Form Requests
Form Requests are where I prefer to keep validation and request-specific authorization. This keeps controllers smaller and places the request rules close to the request itself.
Instead of validating directly inside the controller, create a dedicated request class for the action.
Create A Form Request
Use Artisan to generate a Form Request:
php artisan make:request StorePostRequestLaravel creates the file in:
app/Http/Requests/StorePostRequest.phpBasic Shape
This is the usual structure of a Form Request.
<?php
declare(strict_types=1);
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
final class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'content' => ['nullable', 'string'],
'published' => ['required', 'boolean'],
];
}
}The authorize() method decides if the user can make this request.
The rules() method defines which data is valid.
Use It In A Controller
Type-hint the Form Request in the controller method. Laravel automatically validates the request before the method runs.
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;
Route::post('/posts', [PostController::class, 'store'])
->name('posts.store');use App\Http\Requests\StorePostRequest;
use Illuminate\Http\RedirectResponse;
final readonly class PostController
{
public function store(StorePostRequest $request): RedirectResponse
{
$post = Post::query()->create($request->validated());
return to_route('posts.show', $post)
->with('success', 'Post created successfully.');
}
}If validation fails, the controller method does not run. Laravel redirects back with validation errors.
Validated Data
Use validated() when you want only the fields that passed validation.
$data = $request->validated();This is safer than using all request data because unexpected fields are ignored.
If you only need one validated field, use safe():
$title = $request->safe()->string('title');Authorization
For request-specific permissions, I prefer using the authorize() method on the Form Request instead of creating Gates or Policies.
This keeps the validation and authorization for that request in the same place. If the user is not allowed to make the request, the controller method never runs.
public function authorize(): bool
{
return $this->user()?->isAdmin() ?? false;
}If this returns false, Laravel returns a 403 response before the controller method runs.
This is not better or worse than using Gates or Policies. It is just the approach I prefer because I already use Form Requests for validation, so I do not need extra files for simple request-level authorization.
For larger scoped authorization, like protecting a full admin area, I use middleware.
Custom Messages
Use messages() when the default validation messages are not clear enough.
public function messages(): array
{
return [
'title.required' => 'The post needs a title.',
'published.boolean' => 'Published must be true or false.',
];
}Custom Attribute Names
Use attributes() when you want nicer field names in validation messages.
public function attributes(): array
{
return [
'image_path' => 'image',
];
}Instead of showing image path, Laravel can show image.
Preparing Data
Use prepareForValidation() when the incoming value needs small normalization before validation.
protected function prepareForValidation(): void
{
$this->merge([
'slug' => str($this->string('title'))->slug()->toString(),
]);
}Keep this method small. If the transformation becomes business logic, move it to an Action or service.
Boolean Inputs
HTML checkboxes only send a value when they are checked. A good pattern is to send a hidden default value before the checkbox.
<input type="hidden" name="published" value="0">
<input type="checkbox" name="published" value="1">This ensures that the server always receives a value for published: 0 when unchecked and 1 when checked.
This avoids additional normalization and simplifies validation on the server.
'published' => ['required', 'boolean'],Notes
Use Form Requests when validation has a name and belongs to a specific action, like StorePostRequest, UpdateProfileRequest or UploadAvatarRequest.
For very small one-off validation, inline controller validation can be fine. But once the controller starts growing, move validation into a Form Request.