#
Middleware
Middleware provide a convenient mechanism for inspecting and modifying HTTP requests before sending.
Additional middleware can be written to perform a variety of tasks. For example, a logging middleware might log all outgoing requests and responses.
Middleware is mutable. If you want to apply middleware to only one request, use clone
or ConnectorConfigurator
#
Defining Middleware
To create a new middleware, create a new Invokable class and put your logic inside __invoke
method:
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
final class AttachContentTypeRequestHeader
{
private $contentType;
public function __construct(string $contentType)
{
$this->contentType = $contentType;
}
public function __invoke(RequestInterface $request, callable $next): ResponseInterface
{
return $next($request->withHeader('Content-Type', $this->contentType));
}
}
In this middleware, we will add a content type header to the request depends on the body type.
Middleware also can be a Closure
:
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
function attach_content_type(string $contentType): Closure {
return static function (RequestInterface $request, callable $next): ResponseInterface {
return $next($request->withHeader('Content-Type', $contentType));
};
}
You must call the $next
callback with the $request
to pass the request deeper into the middleware pipeline.
#
Middleware & Responses
Of course, a middleware can perform tasks before or after sending the request. For example, the following middleware would perform some task before the request is sent by the client:
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
final class BeforeMiddleware
{
public function __invoke(RequestInterface $request, callable $next): ResponseInterface
{
// Perform action
return $next($request);
}
}
However, this middleware would perform its task after the request is sent:
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
final class AfterMiddleware
{
public function __invoke(RequestInterface $request, callable $next): ResponseInterface
{
$response = $next($request);
// Perform action
return $response;
}
}
#
Registering Middleware
#
Default Middleware
To register default middleware, list the middleware class in the defaultMiddleware
method of your connector class.
use Fansipan\Contracts\ConnectorInterface;
use Fansipan\Traits\ConnectorTrait;
final class Connector implements ConnectorInterface
{
use ConnectorTrait;
protected function defaultMiddleware(): array
{
return [
new Middleware\AddCustomHeader(),
];
}
}
#
Adding & Removing Middleware
Once the middleware has been created, you may use the push
method to assign middleware to the pipeline:
$connector->middleware()->push(new AddHeader('X-Foo', 'baz'));
Adding middleware to the connector will apply to all requests. If you only want to apply it to the current request, use the middleware
method of ConnectorConfigurator
to create a cloned instance of your connector:
use Fansipan\ConnectorConfigurator;
$response = (new ConnectorConfigurator())
->middleware(new AddHeader('X-Foo', 'baz'))
->configure($connector)
->send(new MyRequest());
Creating a middleware that modifies a request is made much simpler using the Fansipan\Middleware\Interceptor::request()
method. This middleware accepts a function that takes the request argument:
use Fansipan\Middleware\Interceptor;
use Psr\Http\Message\RequestInterface;
$connector->middleware()->push(Interceptor::request(static function (RequestInterface $request) {
return $request->withHeader('X-Foo', 'bar');
}));
Modifying a response is also much simpler using the Fansipan\Middleware\Interceptor::response()
middleware:
use Fansipan\Middleware\Interceptor;
use Psr\Http\Message\ResponseInterface;
$connector->middleware()->push(Interceptor::response(static function (ResponseInterface $response) {
return $response->withHeader('X-Foo', 'bar');
}));
You can give middleware a name, which allows you to add middleware before other named middleware, after other named middleware, or remove middleware by name.
// Add a middleware with a name
$connector->middleware()->push(Interceptor::request(static function (RequestInterface $request) {
return $request->withHeader('X-Foo', 'bar');
}), 'add_foo');
// Add a middleware before a named middleware (unshift before).
$connector->middleware()->before('add_foo', Interceptor::request(static function (RequestInterface $request) {
return $request->withHeader('X-Baz', 'qux');
}), 'add_baz');
// Add a middleware after a named middleware (pushed after).
$connector->middleware()->before('add_baz', Interceptor::request(static function (RequestInterface $request) {
return $request->withHeader('X-Lorem', 'Ipsum');
}));
// Remove a middleware by name
$connector->middleware()->remove('add_foo');