---
title: "Feature: #89216 - PSR-18 HTTP Client Implementation"
manual: "TYPO3 Core Changelog"
version: "main"
permalink: "https://docs.typo3.org/permalink/changelog:feature-89216"
source: "Changelog/10.1/Feature-89216-PSR-18HTTPClientImplementation.rst"
modified: "2026-09-15T10:46:36+00:00"
---

# Feature: #89216 - PSR-18 HTTP Client Implementation

See [forge#89216](https://forge.typo3.org/issues/89216)

## Description

Support for [PSR-18](https://www.php-fig.org/psr/psr-18/) HTTP Client has been added.

PSR-18 HTTP Client is intended to be used by [PSR-15](https://www.php-fig.org/psr/psr-15/) request handlers in order to perform HTTP
requests based on [PSR-7](https://www.php-fig.org/psr/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\ClientInterface`
-   `\Psr\Http\Client\ClientExceptionInterface`
-   `\Psr\Http\Client\NetworkExceptionInterface`
-   `\Psr\Http\Client\RequestExceptionInterface`

Request handlers shall use dependency injection to retrieve the concrete implementation
of the PSR-18 HTTP client interface `\Psr\Http\Client\ClientInterface`.

## Impact

The PSR-18 HTTP Client interface is provided by `psr/http-client` 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](https://www.php-fig.org/psr/psr-17/) Request Factory interface.

Note: This does not replace the currently available Guzzle wrapper
`\TYPO3\CMS\Core\Http\RequestFactory->request()`, 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['TYPO3_CONF_VARS']['HTTP']`
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:

```php
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);
    }
}
```
