Laravel Form Request Validation: Rules, Custom Rules, and Error Handling

Arlind Musliu cofounder at Lucky Media
Arlind Musliu

January 15, 2024 · 6 min read

Laravel for Beginners: Form Requests and Validation Rules

2026 UPDATE - LARAVEL 13

We’re excited to announce that we have updated all of our blog post examples to reflect the new Laravel 13 version! Our previous examples were based on Laravel 10, but with the release of Laravel 13, we wanted to ensure that our readers have access to the most up-to-date information and examples.

Preventing unauthorized entry to your site

In the journey of building an app with Laravel, form requests are your safeguard, ensuring that the content your users contribute is in pair with the standards you’ve set. Laravel’s validation rules enforce these standards, guarding against invalid data.

We will combine the concept of form requests with some common validation rules to illustrate how you can maintain the quality and integrity of your blog’s content.

Creating a Form Request

Let’s start by creating a form request for storing blog posts. This request will ensure that the posts meet our criteria before they’re saved to the database.

php artisan make:request StorePostRequest

This command generates a StorePostRequest class in the app/Http/Requests directory.

Defining Validation Rules in the Form Request

In our StorePostRequest class, we’ll define a set of rules in the rules method to validate the new blog posts:

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
    public function authorize()
    {
        // Allow only logged-in users to create a blog post.
        return auth()->check();
    }

    public function rules()
    {
        return [
            'title' => 'required|max:255|unique:posts',
            'content' => 'required|min:100',
            'image' => 'nullable|image|max:2048',
            'tags' => 'array',
            'tags.*' => 'exists:tags,id'
        ];
    }
}

Let’s break down these validation rules:

  • 'title' => 'required|max:255|unique:posts' ensures that the title field is not empty, it does not exceed 255 characters, and it’s unique in the posts table.

  • 'content' => 'required|min:100' checks that the content is present and is at least 100 characters long, ensuring meaningful blog posts.

  • 'image' => 'nullable|image|max:2048' allows an optional image upload, verifies that the file is indeed an image, and restricts its size to 2MB.

  • 'tags' => 'array' ensures that the tags input is an array, which is useful when selecting multiple tags for a post.

  • 'tags.*' => 'exists:tags,id' checks each item in the tags array to ensure it corresponds to an existing tag ID in the tags table.

Using the Form Request in a Controller

Now that we’ve set up our StorePostRequest, we can use it in our PostController:

namespace App\Http\Controllers;

use App\Http\Requests\StorePostRequest;
use App\Models\Post;

class PostController extends Controller
{
	// other methods

    public function store(StorePostRequest $request)
    {
        // The validated data is automatically retrieved
        $validatedData = $request->validated();
        
        // Create and save the new post with the validated data
        $post = Post::create($validatedData);
        
        // Attach tags if provided
        if ($request->has('tags')) {
            $post->tags()->sync($request->tags);
        }
        
        // Redirect to the new post with a success message
        return redirect()->route('posts.show', $post)
						 ->with('success', 'Post created successfully!');
    }
}

Inline Validation vs Form Request Classes

Laravel gives you two ways to validate incoming data: directly in the controller with $request->validate(), or through a dedicated Form Request class. Both are valid — the right choice depends on your situation.

Inline validation with $request->validate()

Inline validation is the quickest approach and works well for simple endpoints that are only used in one place:

public function store(Request $request)
{
    $validated = $request->validate([
        'title'   => 'required|max:255',
        'content' => 'required|min:100',
    ]);

    Post::create($validated);

    return redirect()->route('posts.index');
}

If validation fails, Laravel automatically redirects back with the errors and old input. For API requests, it returns a 422 JSON response.

When to use a Form Request class

Use a Form Request class when:

  • The same validation logic is reused across multiple controller methods (e.g., store and update).

  • You need custom authorization logic alongside validation.

  • The rules are complex enough that keeping them in the controller makes the method hard to read.

  • You want custom error messages defined in one place using the messages() method.

Custom Validation Rules

Laravel's built-in rules cover most cases, but sometimes you need to validate something specific to your application. You can generate a custom rule class with Artisan:

php artisan make:rule NoSpamWords

This creates app/Rules/NoSpamWords.php. Implement the validate method to define the rule logic:

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class NoSpamWords implements ValidationRule
{
    /**
     * Run the validation rule.
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $spamWords = ['casino', 'free money', 'click here'];

        foreach ($spamWords as $word) {
            if (str_contains(strtolower($value), $word)) {
                $fail("The :attribute contains a prohibited word: {$word}.");
                return;
            }
        }
    }
}

Use the rule in your Form Request or inline validation by passing a new instance:

use App\Rules\NoSpamWords;

public function rules(): array
{
    return [
        'title'   => ['required', 'max:255', new NoSpamWords],
        'content' => ['required', 'min:100', new NoSpamWords],
    ];
}

Conditional Validation

Sometimes a field should only be validated if it is present, or only under certain conditions. Laravel provides two useful rules for this.

The sometimes rule

The sometimes rule tells Laravel: "only validate this field if it is present in the request." This is useful for partial update forms:

public function rules(): array
{
    return [
        // Only validate password if the user actually sent one
        'password' => 'sometimes|required|min:8|confirmed',
    ];
}

The required_if rule

The required_if rule makes a field required only when another field has a specific value. For example, requiring a company name only when the user selects "business" as their account type:

public function rules(): array
{
    return [
        'account_type'  => 'required|in:personal,business',
        'company_name'  => 'required_if:account_type,business|max:255',
    ];
}

Related rules include required_unless, required_with, and required_without — all follow the same pattern of making a field conditionally required based on the presence or value of other fields.

Displaying Validation Errors in Blade

When validation fails, Laravel flashes errors to the session and redirects back to the form. In Blade templates, use the @error directive to show per-field error messages:

<div>
    <label for="title">Title</label>
    <input
        id="title"
        name="title"
        type="text"
        value="{{ old('title') }}"
        class="{{ $errors->has('title') ? 'border-red-500' : '' }}"
    >
    @error('title')
        <p class="text-red-500 text-sm mt-1">{{ $message }}</p>
    @enderror
</div>

Always pair error display with old('field') to restore the user's previously entered value so they do not have to retype the whole form after a validation failure.

To display the first error for a field programmatically (outside of a template directive), use:

// In a Blade template
{{ $errors->first('title') }}

// Check if any errors exist
@if ($errors->any())
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif
laravel best framework php

Conclusion

Form requests and validation rules in Laravel work together to provide a robust system for handling user input. By using these tools, you can ensure that every blog post on your site meets your standards for quality and consistency. The rules help prevent common issues like duplicate titles or insufficient content, while the form requests keep your controller methods clean and focused on their core responsibilities.

Upcoming Articles in the Series

  1. Laravel for Beginners: Task Scheduling for Automation

  2. Laravel for Beginners: Error Handling

  3. Laravel for Beginners: Using Queues

This article is part of our series Laravel for Beginners: A Step-by-Step Guide to Learn the Concepts.


Bring Your Ideas to Life 🚀

If you need help with a Laravel project let’s get in touch.

Lucky Media is proud to be recognized as a leading Laravel Development Agency

Frequently Asked Questions

When should I use a Form Request vs inline validation?

Use inline $request->validate() for simple, one-off rules that do not need to be reused. Use a Form Request class when the rules are complex, when the same rules apply to more than one controller method, or when you want to keep your controller lean. Form Requests also let you define custom error messages and authorization logic alongside validation in a single, testable class.

How do I create a custom validation rule in Laravel?

Run php artisan make:rule RuleName. This creates a class in app/Rules/ with a validate(string $attribute, mixed $value, Closure $fail) method. Call $fail() with an error message to signal that validation failed. Then pass new RuleName as an element in your rules array for any field that needs it.

How do I show validation errors in Blade?

Use the @error('field') directive in your Blade template. Between @error and @enderror, the $message variable contains the first error for that field. Always pair error display with old('field') on the input so users do not lose their entered values on redirect.

Can I validate arrays in Laravel?

Yes. Use the array rule to ensure the field is an array, then use dot-star notation to validate each element. For example, 'tags' => 'array' validates that tags is an array, and 'tags.*' => 'exists:tags,id' validates that every item in the array corresponds to a real tag ID. You can also validate nested arrays using deeper dot notation like 'items.*.quantity' => 'required|integer|min:1'.

Technologies

Laravel
Arlind Musliu cofounder at Lucky Media
Arlind Musliu

Cofounder and CFO of Lucky Media

Stay up-to-date

Be updated with all news, products and tips we share!

Let’s chat

We partner with a limited number of brands each quarter to ensure senior-level attention on every project.

lokman and arlind headshots
Teamwork