Middleware in a Basic Hazaar App
Middleware in a Basic Hazaar App
This example walks through building a small application that uses middleware in practical ways. You will:
- Create a middleware class.
- Register middleware aliases and global middleware in config.
- Attach middleware to specific routes.
- Apply middleware from inside a controller.
- Verify the middleware behavior.
By the end, you will have a working app where:
- Every request receives a request ID.
- API routes can enforce an API key.
- Middleware can pass data to your controllers via request attributes.
Prerequisites
Before you start, make sure you already have a Hazaar app scaffolded and running. If you still need that setup, follow Your First Application first.
Step 1: Create Middleware Classes
Create a middleware directory in your app:
/work/app/Middleware1.1 Add a global request ID middleware
Create RequestId.php in app/Middleware with the following code:
<?php
namespace App\Middleware;
use Hazaar\Application\Request;
use Hazaar\Controller\Response;
use Hazaar\Middleware\Interface\Middleware;
class RequestId implements Middleware
{
public function handle(Request $request, callable $next, mixed ...$args): Response
{
// Create a lightweight request ID and store it on the request.
$requestId = bin2hex(random_bytes(8));
$request->setAttribute('request_id', $requestId);
$response = $next($request);
// Expose the same ID on the response for debugging/tracing.
$response->header('X-Request-ID', $requestId);
return $response;
}
}1.2 Add an API key middleware
Create RequireApiKey.php in app/Middleware:
<?php
namespace App\Middleware;
use Hazaar\Application\Request;
use Hazaar\Controller\Response;
use Hazaar\Controller\Response\JSON;
use Hazaar\Middleware\Interface\Middleware;
class RequireApiKey implements Middleware
{
public function handle(Request $request, callable $next, mixed ...$args): Response
{
// Optional argument lets you override the expected key per route.
$expectedKey = (string) ($args[0] ?? 'dev-api-key');
$providedKey = $request->getHeader('X-API-Key');
if ($providedKey !== $expectedKey) {
return new JSON([
'error' => 'Unauthorized',
'message' => 'Missing or invalid API key.',
], 401);
}
// Pass useful data forward for controllers.
$request->setAttribute('api_client', 'trusted-client');
return $next($request);
}
}Step 2: Register Middleware in App Config
Open your app config file (for example app/Config/app.php) and define middleware aliases plus global middleware:
<?php
return [
'development' => [
'router' => [
'type' => 'file',
'file' => 'routes.php',
],
'middleware' => [
'aliases' => [
'request-id' => \App\Middleware\RequestId::class,
'apikey' => \App\Middleware\RequireApiKey::class,
],
'global' => [
'request-id',
],
],
],
];What this does:
aliasesgives short names you can use in route/controller middleware declarations.globalapplies middleware to every request.
Step 3: Apply Route Middleware
Open your route file (for example app/Config/routes.php) and add middleware to specific endpoints:
<?php
use App\Controller\Dashboard;
use Hazaar\Application\Router;
use Hazaar\Controller\Response\JSON;
Router::get('/', function () {
return 'Hello from Hazaar middleware example';
});
Router::get('/api/ping', function () {
return new JSON(['ok' => true]);
});
// Only this route requires a valid API key.
Router::get('/api/dashboard', [Dashboard::class, 'index'])
->middleware('apikey', 'super-secret-key');At this point:
request-idruns on all routes because it is global.apikeyonly runs for/api/dashboard.
Step 4: Apply Middleware in a Controller
You can also register middleware inside a controller constructor for action-level control.
Create Dashboard.php in app/Controllers:
<?php
namespace App\Controller;
use Hazaar\Controller\Action;
use Hazaar\Controller\Response\JSON;
class Dashboard extends Action
{
public function __construct()
{
// Protect only the index action.
$this->middleware('apikey', 'super-secret-key')->only('index');
}
public function index(): JSON
{
return new JSON([
'message' => 'Dashboard data',
'request_id' => $this->request->getAttribute('request_id'),
'client' => $this->request->getAttribute('api_client'),
]);
}
public function health(): JSON
{
return new JSON(['status' => 'ok']);
}
}Notes:
only('index')means middleware applies toindex()only.- Use
except('actionName')when you want middleware on most actions except specific ones.
Step 5: Test the Flow
Try requests in this order:
GET /should return a normal response and includeX-Request-ID.GET /api/pingshould return JSON without requiring an API key.GET /api/dashboardwithoutX-API-Keyshould return401JSON.GET /api/dashboardwithX-API-Key: super-secret-keyshould return dashboard JSON.
Example curl requests:
curl -i http://localhost/
curl -i http://localhost/api/ping
curl -i http://localhost/api/dashboard
curl -i -H "X-API-Key: super-secret-key" http://localhost/api/dashboardHow This Maps to Middleware Types
- Global middleware:
request-idin configmiddleware.global. - Route middleware:
->middleware('apikey', 'super-secret-key')on/api/dashboard. - Controller middleware:
$this->middleware('apikey', ...)->only('index')in the controller constructor.
This layered approach keeps cross-cutting logic out of your core controller actions while still giving you precise control over where it runs.
Next Steps
- Middleware Overview for full reference and behavior details.
- Routing for advanced route and group patterns.
- Authentication to combine middleware with user sessions and access control.