Laravel form requests for validation
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->can('create', Post::class);
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255', 'unique:posts'],
'body' => ['required', 'string', 'min:100'],
'status' => ['required', Rule::in(['draft', 'published'])],
'published_at' => ['nullable', 'date', 'after:now'],
'tags' => ['array', 'max:5'],
'tags.*' => ['string', 'max:50'],
'featured_image' => ['nullable', 'image', 'max:2048'],
];
}
public function messages(): array
{
return [
'title.unique' => 'A post with this title already exists.',
'body.min' => 'Post content must be at least 100 characters.',
'tags.max' => 'You can add a maximum of 5 tags.',
];
}
public function attributes(): array
{
return [
'published_at' => 'publication date',
'featured_image' => 'image',
];
}
protected function prepareForValidation(): void
{
$this->merge([
'slug' => str($this->title)->slug(),
]);
}
}
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StorePostRequest;
use App\Http\Requests\UpdatePostRequest;
use App\Models\Post;
class PostController extends Controller
{
public function store(StorePostRequest $request)
{
// Validation already passed, authorization already checked
$post = Post::create($request->validated());
if ($request->hasFile('featured_image')) {
$post->addMedia($request->file('featured_image'))
->toMediaCollection('featured');
}
return redirect()
->route('posts.show', $post)
->with('success', 'Post created successfully!');
}
public function update(UpdatePostRequest $request, Post $post)
{
$post->update($request->validated());
return redirect()
->route('posts.show', $post)
->with('success', 'Post updated successfully!');
}
}
Form requests encapsulate validation logic in dedicated classes, keeping controllers thin and focused. Each form request extends FormRequest and defines rules() and optionally authorize() methods. The authorize() method checks if the user can perform the action, returning a 403 if false. Custom error messages go in the messages() method, while attribute names for error display use attributes(). Form requests support conditional validation—rules that apply only when certain conditions are met. The validated() method returns only validated data, preventing mass assignment vulnerabilities. Failed validation automatically redirects back with errors in session. I create separate requests for create and update operations since validation rules often differ.