-
Notifications
You must be signed in to change notification settings - Fork 2
MiddlewarePipeline
Pair\Api\MiddlewarePipeline is the execution engine behind Pair API middleware.
It is the class that turns a list of middleware into one deterministic request flow.
The pipeline works in FIFO order:
- first middleware added = first executed
- last middleware added = closest to the final action
Internally it builds nested closures from the last middleware back to the first, then runs the resulting callable with the current Request.
Appends one middleware to the stack and returns the pipeline itself.
Example:
$pipeline = new \Pair\Api\MiddlewarePipeline();
// Adds CORS first.
$pipeline->add(new \Pair\Api\CorsMiddleware());
// Adds throttling after CORS.
$pipeline->add(new \Pair\Api\ThrottleMiddleware(60, 60));Builds the middleware chain and executes it.
This is the main method of the class.
Example:
$pipeline = new \Pair\Api\MiddlewarePipeline();
$pipeline->add(new FirstMiddleware());
$pipeline->add(new SecondMiddleware());
$pipeline->run($request, function () {
// Final action executed only after all middleware pass.
});Execution order in that example:
FirstMiddleware::handle()SecondMiddleware::handle()- destination callable
The current implementation:
- stores middleware in an internal array
- reverses that array when building the pipeline
- wraps the destination callable step by step
That is why the observable order is FIFO even though the internal closure-building loop runs in reverse.
use Pair\Api\ApiResponse;
use Pair\Api\Middleware;
use Pair\Api\MiddlewarePipeline;
use Pair\Api\Request;
$pipeline = new MiddlewarePipeline();
$pipeline->add(new class implements Middleware {
public function handle(Request $request, callable $next): void
{
// Require JSON before continuing.
if (!$request->isJson()) {
ApiResponse::error('UNSUPPORTED_MEDIA_TYPE');
}
$next($request);
}
});
$pipeline->run($request, function () {
// Final destination.
ApiResponse::respond(['ok' => true]);
});In normal Pair projects you usually do not instantiate MiddlewarePipeline manually.
Instead, ApiController owns one internally and exposes:
$this->middleware(...)$this->runMiddleware(...)
Example:
protected function _init(): void
{
parent::_init();
// Adds CORS to this controller pipeline.
$this->middleware(new \Pair\Api\CorsMiddleware());
// Adds a stricter throttle after the default one.
$this->middleware(new \Pair\Api\ThrottleMiddleware(120, 60));
}
public function meAction(): void
{
$this->runMiddleware(function () {
// Runs only after the middleware stack passes.
\Pair\Api\ApiResponse::respond(['ok' => true]);
});
}MiddlewarePipeline has one important non-public helper:
-
buildPipeline(callable $destination): callableCreates the nested closure chain used byrun().
You normally do not call it directly, but it explains the FIFO behavior.
- Middleware that never calls
$next($request)when it should allow the request. - Middleware that calls
$next()more than once. - Side effects executed after the destination already returned a response.
- Assuming the pipeline reorders middleware automatically. It does not; order is exactly the order you registered.
See also: Middleware, CorsMiddleware, ThrottleMiddleware, ApiController.