Never trusting input is rule one of web development, and Laravel's validation makes it declarative.
The quickest way is $request->validate() in a controller:
$data = $request->validate([
'title' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'unique:users,email'],
'tags' => ['array'], 'tags.*' => ['string', 'distinct'],
]);If validation passes, it returns only the validated fields, which is safe to pass to create(). If it fails, Laravel throws a ValidationException. For a normal form request that means a redirect back with errors and old input flashed to the session (shown via @error and old()); for a request that expects JSON, a 422 response with an errors object.
For anything non-trivial, use a Form Request class: php artisan make:request StorePostRequest. It has rules() and authorize(), and is validated automatically when type-hinted in a controller method, so the controller stays tiny. Read the clean data with $request->validated().
Useful rules: required, nullable, sometimes, string, integer, numeric, boolean, in:a,b, min/max/between, date, after:today, confirmed, exists:table,column, file, image, mimes:pdf. Build complex ones with the Rule class, for example Rule::unique('users')->ignore($user->id) when updating, Rule::enum(Status::class) and Password::min(12)->letters()->numbers(). Custom rule objects come from make:rule.
Example
<?php
namespace App\Http\Requests;
use App\Enums\Status;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdatePostRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->can('update', $this->route('post'));
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'slug' => ['required', 'alpha_dash', Rule::unique('posts')->ignore($this->route('post'))],
'status' => ['required', Rule::enum(Status::class)],
'published_at' => ['nullable', 'date', 'after_or_equal:today'],
];
}
}
// PostController@update(UpdatePostRequest $request, Post $post):
// $post->update($request->validated());
// Bad JSON input -> 422 {"message": "...", "errors": {"title": ["..."]}}Remember
- validate() returns only the validated data, safe for create/update
- Failures redirect back with errors, or return 422 JSON for API clients
- Form Requests hold rules() and authorize() outside the controller
Watch out for
- Validating but then saving $request->all() instead of the validated data.