// tutorial

Move validation into Form Requests

Validating inline with $request->validate() works fine until a controller method has to do it, authorize it, and handle the business logic all at once. A Form Request pulls the validation — and the authorization check — into its own class, so the controller only ever sees data that's already clean.

php laravel validation 6 min read
  1. Generate the request

    The make:request artisan command creates a class in app/Http/Requests with two methods already stubbed out: authorize() and rules().

    bash
    php artisan make:request StoreProductRequest
  2. Decide who's allowed to make this request

    authorize() runs before rules(). Return false and Laravel aborts with a 403 before any validation happens — useful for checking a policy or a simple ownership rule without cluttering the controller.

    php
    public function authorize(): bool
    {
        return $this->user()->can('create', Product::class);
    }

    Most of the time this can just return true; and let a middleware or policy handle authorization elsewhere.

  3. Write the rules

    rules() returns the same array shape as $request->validate() would take — see the next tutorial for everything that can go in here.

    php
    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'price' => 'required|numeric|min:0',
        ];
    }
  4. Type-hint it instead of Request

    Swap the controller method's Request type-hint for the Form Request class. Laravel resolves it out of the container, runs authorize() and rules() automatically, and — on failure — redirects back with the errors flashed to the session for a normal web request, or returns a 422 JSON response for an API call. The controller method body never even runs if validation fails.

    php
    use App\Http\Requests\StoreProductRequest;
    
    public function store(StoreProductRequest $request)
    {
        $product = Product::create($request->validated());
    
        return redirect()->route('products.show', $product);
    }
  5. Use validated(), not all()

    $request->validated() returns only the fields that were actually declared in rules() — so a request stuffed with extra fields can't sneak them into a mass-assignment call. $request->all() would include everything the client sent, validated or not.