http-interop / http-factory-discovery
Utility to locate available HTTP factory implementations
Installs: 146 434
Dependents: 9
Suggesters: 1
Security: 0
Stars: 5
Watchers: 2
Forks: 2
Open Issues: 1
Requires
- php: >=7.1
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
Requires (Dev)
- nyholm/psr7: ^1.0
- php-http/guzzle6-adapter: ^2.0
- phpstan/phpstan: ^0.10.3
- phpstan/phpstan-phpunit: ^0.10.0
- phpunit/phpunit: ^7.3
- squizlabs/php_codesniffer: ^3.3
Suggests
- http-interop/http-factory-diactoros: HTTP Factory implementation for Zend Diactoros
- http-interop/http-factory-guzzle: HTTP Factory implementation for Guzzle
- http-interop/http-factory-slim: HTTP Factory implementation for Slim
- nyholm/psr7: HTTP Messages with Factory implementation
- php-http/guzzle6-adapter: HTTP Client implementation for Guzzle
- sunrise/http-factory: HTTP Messages with Factory implementation
- zendframework/zend-diactoros: HTTP Messages with Factory implementation
README
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:
HTTP Factory
HTTP Client
Additional implementations can be registered.
Install
composer require http-interop/http-factory-discovery
Usage
HTTP Factory
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();
HTTP Client
use Http\Factory\Discovery\HttpClient; /** @var \Psr\Http\Client\ClientInterface */ $client = HttpClient::client();
Best Practices
Because this package acts as a service locator it should be used to supplement dependency injection.
HTTP Factory
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; } } }
HTTP Client
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(); } }
Registering Additional Implementations
Additional implementations can be registered:
HTTP Factory
use Acme\RequestFactory; use Http\Factory\Discovery\FactoryLocator; use Psr\Http\Message\RequestFactoryInterface; FactoryLocator::register(RequestFactoryInterface::class, RequestFactory::class);
HTTP Client
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:
HTTP Factory
use Http\Factory\Discovery\FactoryLocator; use Http\Factory\Guzzle\UriFactory; use Psr\Http\Message\UriFactoryInterface; FactoryLocator::unregister(UriFactoryInterface::class, UriFactory::class);
HTTP Client
use Http\Factory\Discovery\ClientLocator; use Http\Adapter\Guzzle6\Client; use Psr\Http\Client\ClientInterface; ClientLocator::unregister(ClientInterface::class, Client::class);
Clearing Cache
The cache of discovered implementations can be cleared:
HTTP Factory
use Http\Factory\Discovery\HttpFactory; use Psr\Http\Message\UriFactoryInterface; // Clear a single interface HttpFactory::clearCache(UriFactoryInterface::class); // Clear all interfaces HttpFactory::clearCache();
HTTP Client
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.