Emeka Mbah
4 min readSep 27, 2019

--

Taking control of Laravel FormRequest Response

Laravel FormRequest provides a way to handle form validation in a separate class file without cluttering your controller. Keeping your controller slim has many pros which include testable and maintainable code.

Most Artisans still prefer to place validation logic inside a controller method because they wish to have total control over validation failure response and redirection. In this post, I will show you how to use FormRequest and still have full control over responses.

Although Laravel FormRequest handles validation and automatically return appropriate response such JSON or redirect to a form or another page with error messages, you might have a specific situation where you wish to have full control over what is being returned.

Great power comes great responsibility is widely attributed to Uncle Ben — Well not sure if he was the first person to use the phrase. :)

Well, you don’t need to be bitten by a spider before you gain superpowers, One good thing about Laravel is you can easily customize or extend various functionalities.

Let’s dive into examples.
In this example, I will show you how to use FormRequest in the LoginController login method. The purpose of this validation is to ensure the user provides an email and password, it does not check if the credential is valid.

Let us get started by creating a form request. You can easily create a form request with make:request Artisan command

php artisan make:request LoginRequest

The command above generates and place loginRequest.php in app\Http\Request directory

Let’s customize our form request by adding validation rules and modifying validation failure response.

<?php

namespace
App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Validation\ValidationException;


class LoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
*
@return bool
*/
public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
*
@return array
*/
public function rules()
{
return [
'email' => 'required|email',
'password' => 'required|string',
];
}

/**
* Handle a failed validation attempt.
*
*
@param \Illuminate\Contracts\Validation\Validator $validator
*
@return void
*
*
@throws \Illuminate\Validation\ValidationException
*/
protected function failedValidation(Validator $validator)
{
if($this->wantsJson())
{
$response = response()->json([
'success' => false,
'message' => 'Ops! Some errors occurred',
'errors' => $validator->errors()
]);
}else{
$response = redirect()
->route('guest.login')
->with('message', 'Ops! Some errors occurred')
->withErrors($validator);
}

throw (new ValidationException($validator, $response))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
}

As you can see above, we imported two classes

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Validation\ValidationException;

Validator class is used for request validation, you could use the helper function validator() for convenience. ValidationException is required as it throws an important exception

We set authorization to true by returning true from authorize the method this allows any incoming form request to be validated.

public function authorize()
{
return true;
}

Please note that authorize the method is called first and returning false throws AuthorizationException and validation will not be executed.

Next, we overwrite failedValidation method to enable us take control of what is returned on validation failure.

protected function failedValidation(Validator $validator)
{
if($this->wantsJson())
{
$response = response()->json([
'success' => false,
'message' => 'Ops! Some errors occurred',
'errors' => $validator->errors()
]);
}else{
$response = redirect()
->route('guest.login')
->with('message', 'Ops! Some errors occurred')
->withErrors($validator);
}

throw (new ValidationException($validator, $response))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}

You could go wild with many other responses, in this example, we simply included few custom messages in the response.

Lastly, let's attach our LoginRequest to LoginController’s login method

<?php

namespace
App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use App\Http\Requests\LoginRequest;

class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/

use AuthenticatesUsers;

/**
* Where to redirect users after login.
*
*
@var string
*/
protected $redirectTo = '/home';

/**
* Create a new controller instance.
*
*
@return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}


/**
* Validate the user login request.
*
*
@param \App\Http\Requests\LoginRequest $request
*
@return void
*
*
@throws \Illuminate\Validation\ValidationException
*/
protected function validateLogin(LoginRequest $request)
{

}
}

We overwrite validateLogin method and simply type hint LoginRequest which automatically triggers form request validation. We do not have any code in validateLogin method since its called from login method.

Conclusion
In this tutorial, we are able to move validation logic to the form request class and still have control over responses. We are able to include more messages in the validation failure response. We can easily maintain and test our code and reuse our validation logic. Laravel FormRequest is the way to go especially if you are building a big application.

--

--

Emeka Mbah
Emeka Mbah

Written by Emeka Mbah

Emeka is a seasoned software developer passionate about contributing to open-source projects.

Responses (3)