Feature: #89216 - PSR-18 HTTP Client Implementation
See forge#89216
Description
Support for PSR-18 HTTP Client has been added.
PSR-18 HTTP Client is intended to be used by PSR-15 request handlers in order to perform HTTP requests based on PSR-7 message objects without relying on a specific HTTP client implementation.
PSR-18 consists of a client interfaces and three exception interfaces:
\Psr\
Http\ Client\ Client Interface \Psr\
Http\ Client\ Client Exception Interface \Psr\
Http\ Client\ Network Exception Interface \Psr\
Http\ Client\ Request Exception Interface
Request handlers shall use dependency injection to retrieve the concrete implementation
of the PSR-18 HTTP client interface \Psr\
.
Impact
The PSR-18 HTTP Client interface is provided by psr/
and may be used as
dependency for services in order to perform HTTP requests using PSR-7 request objects.
PSR-7 request objects can be created with the PSR-17 Request Factory interface.
Note: This does not replace the currently available Guzzle wrapper
\TYPO3\
, but is available as a framework
agnostic, more generic alternative. The PSR-18 interface does not allow to pass request
specific guzzle options. But global options defined in $GLOBALS
are taken into account as GuzzleHTTP is used as backend for this PSR-18 implementation.
The concrete implementations is internal and will be replaced by a native guzzle PSR-18
implementation once it is available.
Example usage
A middleware might need to request an external service in order to transform the response into a new response. The PSR-18 HTTP client interface is used to perform the external HTTP request. The PSR-17 Request Factory Interface is used to create the HTTP request that the PSR-18 HTTP Client expects. The PSR-7 Response Factory is then used to create a new response to be returned to the user. All off these interface implementations are injected as constructor dependencies:
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class ExampleMiddleware implements MiddlewareInterface
{
/** @var ResponseFactory */
private $responseFactory;
/** @var RequestFactory */
private $requestFactory;
/** @var ClientInterface */
private $client;
public function __construct(
ResponseFactoryInterface $responseFactory,
RequestFactoryInterface $requestFactory,
ClientInterface $client
) {
$this->responseFactory = $responseFactory;
$this->requestFactory = $requestFactory;
$this->client = $client;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if ($request->getRequestTarget() === '/example') {
$req = $this->requestFactory->createRequest('GET', 'https://api.external.app/endpoint.json')
// Perform HTTP request
$res = $this->client->sendRequest($req);
// Process data
$data = [
'content' => json_decode((string)$res->getBody());
];
$response = $this->responseFactory->createResponse()
->withHeader('Content-Type', 'application/json; charset=utf-8');
$response->getBody()->write(json_encode($data));
return $response;
}
return $handler->handle($request);
}
}