Skip to Content
Course content

227: Laravel Form Requests for Validation

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this happen to almost every developer the first time they try to clean up their controllers. You've decided to stop bloating your controller methods with 20 lines of validation rules, so you generate a Form Request class. You type-hint it in your method, hit "Submit" on your form, and instead of your data saving, you get a cold, hard 403 Forbidden response.

The Mystery of the 403 Forbidden

// StorePostController.php
public function store(StorePostRequest $request) 
{
    // I never even reach this line!
    Post::create($request->validated());
}

You check your routes, you check your middleware, and you check your permissions. Everything looks perfect. The problem isn't your routing; it's inside the Form Request class you just generated. When you run php artisan make:request StorePostRequest, Laravel gives you a skeleton that looks like this:

public function authorize(): bool
{
    return false; // <--- This right here is your culprit
}

Laravel assumes that by default, the user is not authorized to make this request. It's a safety feature, but it's a confusing one when you're just trying to get a form to work. If you don't have complex permission logic tied to this specific request yet, you need to flip that switch to true. If you leave it as false, Laravel kills the request before it ever touches your controller logic.

Moving Validation Out of the Controller

Now that we've stopped the 403 errors, let's actually use the Form Request for what it's meant for: removing the noise from your controller. Usually, learners start by doing this in the controller:

public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
        'category_id' => 'required|exists:categories,id',
    ]);

    Post::create($validated);
}

It works, but as your app grows, your controllers become "fat." They start handling authorization, validation, and business logic all in one place. I prefer to move those rules into the rules() method of the StorePostRequest class.

// StorePostRequest.php
public function authorize(): bool
{
    return true; // Now it actually works
}

public function rules(): array
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
        'category_id' => 'required|exists:categories,id',
    ];
}

Once you've done this, your controller method shrinks down to a couple of lines. The magic happens because Laravel automatically calls the rules() method before the controller method is even executed. If validation fails, Laravel automatically redirects the user back to the previous page with the error messages flashed to the session. You don't have to write a single if ($validator->fails()) statement.

Handling the Validated Data

One mistake I often see is people continuing to use $request->all() inside the controller even after moving to a Form Request. Avoid that. Using $request->all() can lead to "mass assignment" vulnerabilities where a malicious user sends an extra field (like is_admin = 1) in the HTTP request, and your app blindly saves it to the database.

Instead, use the validated() method. This ensures you only ever touch data that has actually passed your rules:

public function store(StorePostRequest $request) 
{
    // This returns only the fields defined in your rules() method
    $data = $request->validated(); 
    
    Post::create($data);
    
    return redirect()->route('posts.index');
}

By moving the logic to a Form Request, you've made your code more reusable. If you ever need to create a different controller method (like an API endpoint) that uses the same validation rules, you just type-hint the same Request class and you're done. No more copy-pasting arrays of validation strings across your project.




📋 Practical Task

Build a Validated Support Ticket System

You are building a support ticket system. Your goal is to move the validation logic for creating a ticket out of the controller and into a dedicated Form Request class.

  • The Setup: Create a Form Request class named StoreTicketRequest using the Artisan command.
  • Authorization: Ensure the authorize() method returns true so the request isn't blocked.
  • Validation Rules: In the rules() method, implement the following requirements:
    • subject: Required, string, maximum 100 characters.
    • priority: Required, must be one of the following values: 'low', 'medium', 'high'.
    • description: Required, minimum 20 characters.
    • user_email: Required, must be a valid email address.
  • The Controller: In your TicketController@store method, replace the generic Request $request type-hint with StoreTicketRequest $request and use $request->validated() to retrieve the data for saving.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.