Middleware Pattern
What Is It?
Middleware provides a mechanism to filter and process HTTP requests and responses. Each middleware performs a specific task and passes the request to the next middleware in the chain.
Why?
Cross-cutting concerns (authentication, logging, CORS, rate limiting) apply to many routes. Without middleware, these checks must be duplicated in every controller.
When to Use
For any cross-cutting HTTP concern: authentication, authorization, rate limiting, CORS, logging, input sanitization, response modification.
When Not to Use
For business logic that should be in controllers or services. For one-off checks that only apply to a single endpoint.
Example
Example
<?php
// Custom middleware
class EnsureUserIsActive
{
public function handle(Request $request, Closure $next): Response
{
if (auth()->check() && ! auth()->user()->is_active) {
auth()->logout();
return redirect()->route('login')
->withErrors(['email' => 'Your account has been deactivated.']);
}
return $next($request);
}
}
// Middleware with parameters
class EnsureRole
{
public function handle(Request $request, Closure $next, string ...$roles): Response
{
if (! auth()->check() || ! in_array(auth()->user()->role->slug, $roles)) {
abort(403, 'Unauthorized');
}
return $next($request);
}
}
// Usage in routes
Route::middleware(['auth', 'EnsureUserIsActive'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
Route::middleware('role:admin,super-admin')->group(function () {
Route::resource('users', UserController::class);
});
// Middleware order matters
Route::middleware(['web', 'auth', 'verified'])->group(...);
Pros
- DRY principle for cross-cutting concerns
- Composable and reusable
- Clean separation of HTTP concerns
- Easy to test
- Laravel has built-in middleware support
Cons
- Order matters and can cause bugs
- Hard to debug middleware stack
- Can add processing overhead
- Too many middleware layers reduce readability