Summary - Middleware
Build a protected API route structure with auth, logging and PSR-15.
Summary - Middleware
In this group you learned the middleware pattern, the before/after idea, building a pipeline with array_reduce, auth and logging layers, and the PSR-15 interface.
Now combine them: chain auth and logging middlewares with buildPipeline and observe different outputs for guest and member requests. Then write a PSR-15 style ErrorHandler class that catches exceptions and returns a clean response.
These two tasks give you practice using both callable and class based middleware in the same project.
Exercise Auth + logging pipeline
Define three functions: authMiddleware, loggingMiddleware and buildPipeline. authMiddleware returns "unauthorized" when $_SESSION['user_id'] is missing (early return); otherwise it returns $next($request). loggingMiddleware prints "[LOG] {$request}" and returns $next($request). buildPipeline uses array_reduce and array_reverse to produce a wrapping callable. Build the pipeline and call it twice: first as guest, then as a member; print the results.
Show example solution
Write function authMiddleware($request, $next) { if (!isset($_SESSION['user_id'])) { return "unauthorized"; } return $next($request); } and function loggingMiddleware($request, $next) { echo "[LOG] {$request}\n"; return $next($request); }. Reuse buildPipeline from the previous lesson. Then $pipeline = buildPipeline(['loggingMiddleware', 'authMiddleware'], $finalHandler); unset($_SESSION['user_id']); echo $pipeline("panel") . "\n"; $_SESSION['user_id'] = 42; echo $pipeline("panel") . "\n";.
Example solution:
<?php
function authMiddleware($request, $next) {
if (!isset($_SESSION['user_id'])) {
return "unauthorized";
}
return $next($request);
}
function loggingMiddleware($request, $next) {
echo "[LOG] {$request}\n";
return $next($request);
}
function buildPipeline(array $middlewares, callable $handler): callable {
return array_reduce(array_reverse($middlewares), function ($next, $mw) {
return function ($request) use ($mw, $next) {
return $mw($request, $next);
};
}, $handler);
}
session_start();
$finalHandler = function ($request) {
return "DONE";
};
$pipeline = buildPipeline(['loggingMiddleware', 'authMiddleware'], $finalHandler);
unset($_SESSION['user_id']);
echo $pipeline("panel") . "\n";
$_SESSION['user_id'] = 42;
echo $pipeline("panel") . "\n";
Exercise A PSR-15 style ErrorHandler
Define an ErrorHandler class that mimics the PSR-15 structure. Give it a public function process($request, $handler) method. Inside, wrap try { return $handler->handle($request); } with a catch (\Exception $e); on error return "ERROR: " . $e->getMessage(). FinalHandler and CrashHandler are already defined. Instantiate the ErrorHandler, call process with both handlers and print the results.
Show example solution
" . $e->getMessage(); } } }. Then $eh = new ErrorHandler(); echo $eh->process("istek", new FinalHandler()) . "\n"; echo $eh->process("istek", new CrashHandler()) . "\n";.
Example solution:
<?php
class ErrorHandler {
public function process($request, $handler) {
try {
return $handler->handle($request);
} catch (\Exception $e) {
return "ERROR: " . $e->getMessage();
}
}
}
class FinalHandler {
public function handle($request) {
return "DONE";
}
}
class CrashHandler {
public function handle($request) {
throw new \Exception("server error");
}
}
$eh = new ErrorHandler();
echo $eh->process("istek", new FinalHandler()) . "\n";
echo $eh->process("istek", new CrashHandler()) . "\n";
Test yourself
-
Match all the middleware concepts
- $next
- Moves to the next step
- array_reduce
- Builds the pipeline
- Auth
- Verifies the session
- PSR-15
- Standard interface
-
When does the first middleware in a pipeline run?
- Never
- Last, when the response returns
- First, as the outer layer
- Only on errors
Show answer
First, as the outer layer — Correct. The first middleware is the outer layer; its before runs first.