Package for automatic discovery of available implementations providing HTTP functionality. Allows for fast switching between different implementations with minimal effort.
Automatic discovery of HTTP Factories and HTTP Clients is supported.
By default, the following implementations can be discovered:
Additional implementations can be registered.
composer require http-interop/http-factory-discovery
use Http\Factory\Discovery\HttpFactory;
/** @var \Psr\Http\Message\RequestFactoryInterface */
$requestFactory = HttpFactory::requestFactory();
/** @var \Psr\Http\Message\ResponseFactoryInterface */
$responseFactory = HttpFactory::responseFactory();
/** @var \Psr\Http\Message\ServerRequestFactoryInterface */
$serverRequestFactory = HttpFactory::serverRequestFactory();
/** @var \Psr\Http\Message\StreamFactoryInterface */
$streamFactory = HttpFactory::streamFactory();
/** @var \Psr\Http\Message\UriFactoryInterface */
$uriFactory = HttpFactory::uriFactory();
/** @var \Psr\Http\Message\UploadedFileFactoryInterface */
$uploadedFileFactory = HttpFactory::uploadedFileFactory();
use Http\Factory\Discovery\HttpClient;
/** @var \Psr\Http\Client\ClientInterface */
$client = HttpClient::client();
Because this package acts as a service locator it should be used to supplement dependency injection.
A prime example for using HTTP Factories would be when writing PSR-15 middleware:
namespace Acme\Middleware;
use Http\Factory\Discovery\HttpFactory;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface as Handler;
class CatchErrors extends MiddlewareInterface
{
/** @var ResponseFactoryInterface */
private $responseFactory;
/** @var StreamFactoryInterface */
private $streamFactory;
public function __construct(
ResponseFactoryInterface $responseFactory = null,
StreamFactoryInterface $streamFactory = null
) {
$this->responseFactory = $responseFactory ?? HttpFactory::responseFactory();
$this->streamFactory = $streamFactory ?? HttpFactory::streamFactory();
}
public function process(Request $request, Handler $handler): Response
{
try {
return $handler->handle($request);
} catch (\Throwable $error) {
$stream = $this->streamFactory->createStream($e->getMessage());
$response = $this->responseFactory->createResponse(500);
$response = $response->withHeader('content-type', 'text/plain');
$response = $response->withBody($stream);
return $response;
}
}
}
An example for using both HTTP Client and HTTP Factories would be when writing functionality sending HTTP requests:
namespace Acme;
use Http\Factory\Discovery\HttpClient;
use Http\Factory\Discovery\HttpFactory;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
class Api
{
/** @var ClientInterface */
private $client;
/** @var RequestFactoryInterface */
private $requestFactory;
public function __construct(
ClientInterface $client = null,
RequestFactoryInterface $requestFactory = null
) {
$this->client = $client ?? HttpClient::client();
$this->requestFactory = $requestFactory ?? HttpFactory::requestFactory();
}
public function query(): string
{
$request = $this->requestFactory->createRequest('GET', 'http://acme.com/api');
return $this->client->sendRequest($request)->getBody()->getContents();
}
}
Additional implementations can be registered:
use Acme\RequestFactory;
use Http\Factory\Discovery\FactoryLocator;
use Psr\Http\Message\RequestFactoryInterface;
FactoryLocator::register(RequestFactoryInterface::class, RequestFactory::class);
use Acme\Client;
use Http\Factory\Discovery\ClientLocator;
use Psr\Http\Client\ClientInterface;
ClientLocator::register(ClientInterface::class, Client::class);
Implementations can also be unregistered, if you prefer not to use them:
use Http\Factory\Discovery\FactoryLocator;
use Http\Factory\Guzzle\UriFactory;
use Psr\Http\Message\UriFactoryInterface;
FactoryLocator::unregister(UriFactoryInterface::class, UriFactory::class);
use Http\Factory\Discovery\ClientLocator;
use Http\Adapter\Guzzle6\Client;
use Psr\Http\Client\ClientInterface;
ClientLocator::unregister(ClientInterface::class, Client::class);
The cache of discovered implementations can be cleared:
use Http\Factory\Discovery\HttpFactory;
use Psr\Http\Message\UriFactoryInterface;
// Clear a single interface
HttpFactory::clearCache(UriFactoryInterface::class);
// Clear all interfaces
HttpFactory::clearCache();
use Http\Factory\Discovery\HttpClient;
use Psr\Http\Client\ClientInterface;
// Clear a single interface
HttpClient::clearCache(ClientInterface::class);
// Clear all interfaces
HttpClient::clearCache();
Note: Cache is automatically cleared when FactoryLocator::unregister()
or
ClientLocator::unregister()
is called.