Laravel 5/6— Tips on Validation

Wei Hien
Wei Hien
Jan 12 · 3 min read
Photo by Jose Aragones on Unsplash

When creating an application or API endpoint, one of the most often neglected part is validation on the request. After all, why bother adding limitations if it is already working as intended?

However, neglecting this part might cause more problem down the road. We shouldn’t expect users to always submit data in intended format. Moreover, front-end validation could be easily modified/disabled by user.

Here, I would like to share some tips I’ve been using for Laravel validation. They are all in Form Request format.


1

Form Request has been introduced since Laravel 5.0. It is recommended to place the validation logics in Form Request, especially when the logics are complex.

It’s easy to read when your controller methods are written like this:

public function store(CreateBookRequest $request)
{
$this->authorize(Book::class, 'create');
$book = Book::create($request->all()); return BookResource::make($book);
}

All validation logics are handled within the Form Request class -CreateBookRequest.

While conforming to the recommended Thin Controller practice, it’s clear at a glance that this controller method only focus on handling the request logic.

2

Sometimes you might need to validate differently according to different conditions. One way to cater for this is to use rule such as requiredIf.

As shown from Laravel docs:

use Illuminate\Validation\Rule;

Validator::make($request->all(), [
'role_id' => Rule::requiredIf($request->user()->is_admin),
]);

However if the conditions for validations are complex, it may become too troublesome to specify this for every parameters. Moreover, this is only applicable to required and some other rules only.

If we look at the Form Request rules() method, it is actually returning just an array. Therefore in this case, it might be easier to directly construct the returned array:

$rule = [
// Rules applicable to all condition...
];
if ($request->user()->is_admin) {
$rule += [
'role_id' => ['required'],
// Other rules if user is admin...
];
}
return $rule;

3

Most of the relational DBMS now supports JSON column type. For some data field that changes very frequently in structure, you might prefer to store them in JSON column instead of creating tons of migrations.

Since version 5.2, Laravel could accept JSON request as long as you set the request header to content-type: application/json. Under the hood, Laravel would then run json_decode(payload, true) and parse the JSON payload into associative array.

Therefore, you could validate the JSON request as if from traditional form. For example, if you are expecting the request JSON payload to be as follows:

{
"title": "Laravel 6",
"tags": ["Laravel", "Awesome", "PHP"],
"publication": {
"date" : "2020-10-10",
"publisher": "Laravel Inc"
}
}

You could validate with rules as follows:

public function rules() {
return [
"title" => "required",
"tags" => "required|array|min:1",
"tags.*" => "required",
"publication" => "required|array",
"publication.date" => "required|date",
"publication.publisher" => "required",
];
}

4

For any validation rules that you are unable to specify within rules(), you may use withValidator() method, which is an “after” hook to a Form Request.

As shown from Laravel docs:

public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong
with this field!');
}
});
}

Should the validation fails, the error added to validator here would be appended to the ‘errors’ in response.

It is also possible to add in custom validations and merge it here. For example, sometimes you want to validate existing fields which are not part of the request:

/**
* These informations are optional when the book is created.
* But when the book is put on sale, need to validate that these
* informations are correct.
*/
public function rules()
{
return [
'ready_for_sale' => 'required|boolean',
];
}
public function withValidator($validator)
{
$validator->after(function ($validator) {

if ($this->ready_for_sale) {
$additionalValidator = validator(
$this->book->toArray(), [
'title' => 'required',
'isbn' => 'required',
'price' => 'required|numeric'
]
);
$validator->errors()->merge($additionalValidator);
}

});
}

Thanks for reading through! Feel free to leave any comment or contact me on weihien90@gmail.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade