VOOZH about

URL: https://deepwiki.com/hypervel/api-client/7-middleware-system

⇱ Middleware System | hypervel/api-client | DeepWiki


Loading...
Menu

Middleware System

The middleware system provides extensible interception points for modifying requests before they are sent to the API and responses after they are received. This system implements a pipeline pattern where middleware components can be chained to process ApiRequest and ApiResponse objects sequentially. The middleware architecture separates request-side transformations (authentication, header injection, logging) from response-side transformations (data normalization, error handling, caching).

For information about configuring requests and responses without middleware, see Making Requests and Response Handling. For details on context passing through the request/response lifecycle, see HasContext Trait.

Architecture Overview

The middleware system consists of two independent pipelines that wrap the HTTP execution layer:

  1. Request Pipeline: Processes ApiRequest objects before HTTP transmission
  2. Response Pipeline: Processes ApiResponse objects after HTTP reception

Both pipelines are orchestrated by PendingRequest, which manages middleware registration, execution, and caching. The ApiClient class defines default middleware configuration that is inherited by each PendingRequest instance, allowing both global and per-request middleware customization.


Sources: src/PendingRequest.php22-62 src/PendingRequest.php265-291 src/ApiClient.php14-36

Pipeline Execution Flow

The middleware execution follows a precise sequence within the request lifecycle. The PendingRequest::sendRequest() method coordinates the entire flow, using the beforeSending() hook to inject request middleware and processing response middleware after HTTP execution.


Sources: src/PendingRequest.php265-291 src/PendingRequest.php293-307

Request Middleware

Request middleware processes ApiRequest objects before they are converted to PSR-7 requests and sent via the HTTP client. This pipeline executes within the beforeSending() callback in src/PendingRequest.php272-278

Execution Context

Request middleware receives:

  • The ApiRequest object with context containing middlewareOptions via withContext('options', ...) at src/PendingRequest.php296
  • Access to all request properties (URL, method, headers, body data)
  • The ability to return a modified ApiRequest object

Registration

Request middleware is registered through:

MethodScopeLocation
ApiClient::$requestMiddlewareGlobal (all requests)src/ApiClient.php31
PendingRequest::withRequestMiddleware()Per-request (replaces)src/PendingRequest.php107-112
PendingRequest::withAddedRequestMiddleware()Per-request (appends)src/PendingRequest.php117-122

Sources: src/PendingRequest.php293-299 src/PendingRequest.php38-40 src/ApiClient.php31-32

Response Middleware

Response middleware processes ApiResponse objects after HTTP execution but before transformation to ApiResource. This pipeline executes in src/PendingRequest.php286-288

Execution Context

Response middleware receives:

  • The ApiResponse object with context containing middlewareOptions via withContext('options', ...) at src/PendingRequest.php304
  • Access to all response properties (status code, headers, body)
  • The ability to return a modified ApiResponse object

Registration

Response middleware is registered through:

MethodScopeLocation
ApiClient::$responseMiddlewareGlobal (all requests)src/ApiClient.php35
PendingRequest::withResponseMiddleware()Per-request (replaces)src/PendingRequest.php127-132
PendingRequest::withAddedResponseMiddleware()Per-request (appends)src/PendingRequest.php137-142

Sources: src/PendingRequest.php301-307 src/PendingRequest.php43-45 src/ApiClient.php35-36

Middleware Instantiation and Caching

The PendingRequest::createMiddleware() method at src/PendingRequest.php309-326 handles middleware instantiation with a caching mechanism to optimize performance.

Instantiation Process


Caching Behavior

  • Middleware instances are stored in PendingRequest::$cachedMiddleware static property at src/PendingRequest.php51
  • Each middleware class is instantiated once per application lifecycle
  • Middleware constructors receive ApiClient::getConfig() for configuration access
  • The cache can be flushed via PendingRequest::flushCache() at src/PendingRequest.php249-252

Sources: src/PendingRequest.php309-326 src/PendingRequest.php51 src/PendingRequest.php249-252

Middleware Control and Configuration

Enable/Disable Control

Middleware execution can be controlled at both the ApiClient and PendingRequest levels:

ClassPropertyMethodsDefault
ApiClientenableMiddleware at src/ApiClient.php26enableMiddleware(), disableMiddleware() at src/ApiClient.php76-91true
PendingRequestenableMiddleware at src/PendingRequest.php31enableMiddleware(), disableMiddleware() at src/PendingRequest.php67-82Inherited from ApiClient

When enableMiddleware is false, both request and response pipelines are skipped entirely at src/PendingRequest.php274 and src/PendingRequest.php286

Middleware Options

The middlewareOptions array provides runtime context to middleware components:

Guzzle Options

Separate from middleware options, Guzzle-specific HTTP client options can be set:

Sources: src/PendingRequest.php31-35 src/PendingRequest.php67-102 src/ApiClient.php26 src/ApiClient.php76-91

Creating Custom Middleware

Custom middleware classes must follow these conventions:

  1. Constructor Signature: Accept an optional DataObject configuration parameter
  2. Invocation: Implement __invoke(ApiRequest|ApiResponse $subject, Closure $next) method
  3. Pipeline Contract: Return the result of $next($subject) to continue the chain

Middleware Structure Pattern

Middleware classes are instantiated at src/PendingRequest.php322 with the signature new $middlewareClass($this->client->getConfig()). The typical structure is:

class CustomMiddleware
{
 public function __construct(?DataObject $config = null)
 {
 // Store configuration if needed
 }
 
 public function __invoke(ApiRequest|ApiResponse $subject, Closure $next)
 {
 // Access middleware options
 $options = $subject->context('options');
 
 // Modify $subject (request or response)
 // ...
 
 // Continue pipeline
 return $next($subject);
 }
}

Context Access

Middleware can access runtime options through the HasContext trait methods on ApiRequest and ApiResponse:

Sources: src/PendingRequest.php309-326 src/PendingRequest.php293-307

Pipeline Implementation Details

The middleware system uses the Pipeline class from hypervel/support:


The pipeline is created at src/PendingRequest.php61 and stored as a property. Each middleware execution creates a chain where:

  1. send() sets the initial subject (ApiRequest or ApiResponse)
  2. through() provides the middleware array from createMiddleware()
  3. thenReturn() executes the chain and returns the final subject

Sources: src/PendingRequest.php49 src/PendingRequest.php61 src/PendingRequest.php293-307

Error Handling

The middleware system enforces several validation rules:

ValidationLocationException
Middleware class existssrc/PendingRequest.php313-316InvalidArgumentException
Async requests not supportedsrc/PendingRequest.php280-282InvalidArgumentException
Resource class existssrc/PendingRequest.php152-156InvalidArgumentException
Resource extends ApiResourcesrc/PendingRequest.php158-162InvalidArgumentException

Sources: src/PendingRequest.php280-282 src/PendingRequest.php309-326