http-interop/http-factory
http-interop/http-factory defines standard interfaces for creating PSR-7 HTTP messages and URIs, providing a PSR-17 precursor API that decouples your code from concrete HTTP implementations. Install via Composer for interoperable factory support.
This package is an implementation of the PSR-17 HTTP factory interfaces (RequestFactoryInterface, ResponseFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, UriFactoryInterface). In a Laravel app you'll reach for it when something needs to create PSR-7 messages rather than consume them — custom streamed responses, building requests for a PSR-18 client, or satisfying a third-party package that type-hints a factory interface.
Read the release note first: 0.4.1 is the final release and the package is deprecated. That changes the "getting started" step from "install it" to "decide whether to install it at all."
composer show | grep -i psr
composer why psr/http-factory
Guzzle pulls in guzzlehttp/psr7, which already provides factories. If that's present, you likely don't need this package.composer require <vendor>/<package>:^0.4.1
ResponseFactoryInterface into a controller or a small action class and return $responseFactory->createResponse(200)->withBody($streamFactory->createStream($json)). If that round-trips through your test suite, the wiring is correct.For new work, start on the replacement path instead: composer require psr/http-factory (interfaces) plus a maintained implementation such as nyholm/psr7 or guzzlehttp/psr7, and bind those factories in your own service provider.
Bind interfaces, never concrete classes. The whole value of PSR-17 is that your code type-hints Psr\Http\Message\ResponseFactoryInterface. Register the bindings in a PsrServiceProvider so that replacing the implementation later is a one-line change in a provider rather than a search-and-replace across the app:
$this->app->bind(ResponseFactoryInterface::class, fn () => new ResponseFactory());
$this->app->bind(StreamFactoryInterface::class, fn () => new StreamFactory());
// ...request, uri, uploaded file
Factory + PSR-18 client is the common pairing. Factories create the request, the client sends it. Keeping the factory injection separate from the client injection makes tests trivial: swap the client for a mock, leave the factory real.
Use factories in custom responses. Laravel's Response doesn't speak PSR-7, so if a package hands you a StreamInterface you need a stream factory to build one from a string or a resource, and a response factory to wrap it. A small StreamedJsonResponse-style class is the usual home for this.
Prefer factories over new Response(...) in reusable code. If you're writing a package or a shared domain service, new-ing a concrete PSR-7 class couples you to one implementation. Inject the factory instead — even if today there's only one implementation in the tree.
Test doubles are cheap. A fake ResponseFactoryInterface returning a real Response is a few lines; use it in unit tests so you never boot the container just to get a message object.
Migration pattern for the deprecation. Because the interfaces are the stable contract, the swap is mechanical: add psr/http-factory + a maintained implementation, point your existing bindings at the new concrete classes, remove this package. Anything type-hinting the interfaces — which should be everything — keeps compiling. Do it as two commits (add+bind, then remove) so a rollback is clean.
psr/http-factory is interfaces only. The release note's advice is correct but incomplete: switching to psr/http-factory gives you the contracts, not a working factory. You must also pick an implementation (nyholm/psr7, guzzlehttp/psr7, laminas-diactoros). Don't swap the dependency and assume factories still resolve — the container binding will fail at runtime, not at boot.guzzlehttp/psr7 is already on disk and already satisfies the interfaces. Two implementations means two sets of bindings and confusing composer why output. Audit before adding anything.0.x versions carry no BC promise. Even before the abandonment notice, a 0.4 → 0.5 bump was allowed to break signatures. Pin to ^0.4.1 and note the pin in your upgrade docs.StreamInterface instances in the container.Target [Psr\Http\Message\ResponseFactoryInterface] is not instantiable, the provider isn't registered or the package's auto-discovery is disabled in composer.json. Run php artisan about / check bootstrap/providers.php and config/app.php for the provider entry.grep -rn "Psr\\\\Http\\\\Message" app/ to confirm nothing type-hints a concrete class from this package. Anything that does is the actual blocker for migration.How can I help you explore Laravel packages today?