Creating Custom Middleware
There are three main approaches to creating custom middleware:- Implementing the
HttpMiddleware
interface directly - Extending the
BaseMiddleware
abstract class - Using anonymous classes for simple middleware
Approach 1: Implementing HttpMiddleware Interface
The most direct approach is to implement theHttpMiddleware
interface:
Approach 2: Extending BaseMiddleware
For most cases, extending theBaseMiddleware
abstract class is more convenient:
BaseMiddleware
, you only need to override the methods that matter for your middleware:
beforeRequest(HttpClientRequest $request): void
- Called before the request is sentafterRequest(HttpClientRequest $request, HttpResponse $response): HttpResponse
- Called after the response is receivedshouldDecorateResponse(HttpClientRequest $request, HttpResponse $response): bool
- Determines if the response should be decoratedtoResponse(HttpClientRequest $request, HttpResponse $response): HttpResponse
- Creates a decorated response
Approach 3: Using Anonymous Classes
For simple middleware that you only need to use once, you can use anonymous classes:Practical Middleware Examples
Retry Middleware
This middleware automatically retries failed requests:Rate Limiting Middleware
This middleware throttles requests to respect API rate limits:Caching Middleware
This middleware caches responses for GET requests:Response Decoration
Response decoration is a powerful technique for wrapping HTTP responses to add functionality or transform data. It’s particularly useful for streaming responses, where you need to process each chunk as it arrives.Creating a Response Decorator
All response decorators should implement theHttpResponse
interface. The library provides a BaseResponseDecorator
class that makes this easier:
Using Response Decorators in Middleware
To use a response decorator, you need to create a middleware that wraps the response:Response Decoration for Transforming Content
You can use response decoration to transform response content on-the-fly:Advanced Middleware Examples
Here are some more advanced middleware examples that demonstrate the power and flexibility of the middleware system.Analytics Middleware
This middleware collects analytics data about HTTP requests:Circuit Breaker Middleware
This middleware implements the circuit breaker pattern to prevent repeated calls to failing services:Conditional Middleware
This middleware only applies to certain requests based on a condition:Request ID Middleware
This middleware adds a unique ID to each request and tracks it through the response:OpenTelemetry Tracing Middleware
This middleware adds OpenTelemetry tracing to HTTP requests:Customizing Middleware for LLM APIs
When working with Large Language Model (LLM) APIs, you can create specialized middleware to handle their unique requirements:Combining Multiple Middleware Components
When building complex applications, you’ll often need to combine multiple middleware components. Here’s an example of how to set up a complete HTTP client pipeline:- Request Flow (outside → inside):
- TracingMiddleware: Starts a trace
- LoggingMiddleware: Logs the outgoing request
- CircuitBreakerMiddleware: Checks if the service is available
- CachingMiddleware: Checks if response is cached
- AuthenticationMiddleware: Adds authentication headers
- RetryMiddleware: Prepares to retry on failure
- RateLimitingMiddleware: Enforces rate limits
- AnalyticsMiddleware: Starts timing
- HTTP Driver: Sends the actual request
- Response Flow (inside → outside):
- HTTP Driver: Receives the response
- AnalyticsMiddleware: Records API stats
- RateLimitingMiddleware: Updates rate limit counters
- RetryMiddleware: Handles retries if needed
- AuthenticationMiddleware: Verifies authentication status
- CachingMiddleware: Caches the response
- CircuitBreakerMiddleware: Updates circuit state
- LoggingMiddleware: Logs the response
- TracingMiddleware: Completes the trace
- Your Application: Processes the final response