Validation and form requests

Laravel · Practical · 14 min

Never trusting input is rule one of web development, and Laravel's validation makes it declarative.

The quickest way is $request->validate() in a controller:

$data = $request->validate([
    'title' => ['required', 'string', 'max:255'],
    'email' => ['required', 'email', 'unique:users,email'],
    'tags' => ['array'], 'tags.*' => ['string', 'distinct'],
]);

If validation passes, it returns only the validated fields, which is safe to pass to create(). If it fails, Laravel throws a ValidationException. For a normal form request that means a redirect back with errors and old input flashed to the session (shown via @error and old()); for a request that expects JSON, a 422 response with an errors object.

For anything non-trivial, use a Form Request class: php artisan make:request StorePostRequest. It has rules() and authorize(), and is validated automatically when type-hinted in a controller method, so the controller stays tiny. Read the clean data with $request->validated().

Useful rules: required, nullable, sometimes, string, integer, numeric, boolean, in:a,b, min/max/between, date, after:today, confirmed, exists:table,column, file, image, mimes:pdf. Build complex ones with the Rule class, for example Rule::unique('users')->ignore($user->id) when updating, Rule::enum(Status::class) and Password::min(12)->letters()->numbers(). Custom rule objects come from make:rule.

Example

<?php
namespace App\Http\Requests;

use App\Enums\Status;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdatePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('update', $this->route('post'));
    }
    public function rules(): array
    {
        return [
            'title' => ['required', 'string', 'max:255'],
            'slug' => ['required', 'alpha_dash', Rule::unique('posts')->ignore($this->route('post'))],
            'status' => ['required', Rule::enum(Status::class)],
            'published_at' => ['nullable', 'date', 'after_or_equal:today'],
        ];
    }
}
// PostController@update(UpdatePostRequest $request, Post $post):
//     $post->update($request->validated());
// Bad JSON input -> 422 {"message": "...", "errors": {"title": ["..."]}}

Remember

  • validate() returns only the validated data, safe for create/update
  • Failures redirect back with errors, or return 422 JSON for API clients
  • Form Requests hold rules() and authorize() outside the controller

Watch out for

  • Validating but then saving $request->all() instead of the validated data.

Check yourself

  1. An API client sends JSON with Accept: application/json and fails validation. What does it receive?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: laravel.com/docs/12.x/validation