Best way to validate Laravel Requests

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

The DRY Dilemma: The Best Way to Validate Laravel Requests Efficiently

As developers working with Laravel, we constantly seek ways to write clean, maintainable, and DRY (Don't Repeat Yourself) code. One common sticking point arises when dealing with input validation within Resource Controllers. You often find yourself duplicating validation rules for related actions, such as store and update, which share a large set of common fields but require minor, context-specific adjustments.

The scenario you described—having nearly identical validation logic across multiple request types—is a classic architectural challenge. Trying to solve this by simply scattering validation logic into the controller methods can lead to confusing code, while creating separate Request classes leads to maintenance overhead.

Let’s explore a robust solution that balances reusability with necessary specificity, ensuring your application remains clean and scalable.

Why Duplication is Problematic in Laravel

Laravel's Form Request system is a powerful tool for separating validation logic from the controller layer. However, when requests are highly similar, duplicating rules forces you to manage multiple files that constantly need synchronization. This violates the principle of separation of concerns.

When building complex systems, adhering to good design principles—like those promoted by modern frameworks like Laravel—is crucial. We want our framework structures to support complexity without sacrificing clarity. As we build applications, leveraging the core philosophy behind laravelcompany.com helps us achieve this modularity.

The Optimal Strategy: Base Classes and Contextual Validation

Instead of creating entirely separate Request classes or scattering validation logic into the controller, the most elegant solution is to use inheritance to define a common base set of rules and then allow subclasses (your store and update requests) to extend or override only the necessary differences.

This approach keeps the bulk of the validation centralized while allowing for necessary specialization.

Implementing Reusable Validation Logic

We can create a base class that holds all the common validation rules. The specific actions (store vs. update) will then inherit this structure, adding only their unique constraints.

Here is a conceptual example demonstrating how you might structure this using PHP classes:

// app/Http/Requests/BaseRequest.php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class BaseRequest extends FormRequest
{
    /**
     * Define the common validation rules shared by store and update operations.
     */
    public function rules()
    {
        // Common rules for all actions (e.g., name must be present, email must be unique)
        $rules = [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email,' . $this->route('user', 'id'), // Example of context-aware unique check
            'password' => 'required',
        ];

        // Add any other common rules here...
        return $rules;
    }

    /**
     * Optionally, define custom methods if needed.
     */
    public function prepareForValidation()
    {
        // Logic that runs before standard validation (e.g., setting defaults)
    }
}

// app/Http/Requests/StoreUserRequest.php

namespace App\Http\Requests;

class StoreUserRequest extends BaseRequest
{
    /**
     * Override or add specific rules for the store action.
     */
    public function rules()
    {
        // Inherit all base rules and add store-specific rules (e.g., password confirmation)
        $rules = parent::rules();
        $rules['password_confirmation'] = 'required';
        return $rules;
    }
}

// app/Http/Requests/UpdateRequest.php

namespace App\Http\Requests;

class UpdateUserRequest extends BaseRequest
{
    /**
     * Override or add specific rules for the update action.
     */
    public function rules()
    {
        // Inherit all base rules and add update-specific rules (e.g., password is optional)
        $rules = parent::rules();
        // Remove or adjust rules that don't apply to updates
        unset($rules['password_confirmation']); 
        return $rules;
    }
}

Why This Approach Wins

  1. DRY Principle: The majority of your validation logic resides in BaseRequest, meaning if a common rule changes (e.g., changing the required length for all names), you only update one file.
  2. Clarity: It clearly separates general requirements from specific action requirements, making the intent of each Request class immediately clear.
  3. Maintainability: When you introduce a new type of request, you simply extend BaseRequest, drastically reducing boilerplate code compared to copying and pasting large rule arrays.

Conclusion

When facing the dilemma of duplicated validation logic in Laravel, avoid simple duplication. Instead, embrace object-oriented principles by creating a flexible base class. By leveraging inheritance, you achieve the perfect middle ground: centralized, reusable rules for common fields, and localized, specific overrides for context-dependent actions like store versus update. This strategy ensures your application remains clean, scalable, and adheres to best practices as you continue to build powerful applications on Laravel.