http-interop/http-factory-diactoros
PSR-17 HTTP factory implementations backed by Zend Diactoros. Create requests, responses, streams, and URIs through the standard HttpFactory interfaces, giving projects a lightweight bridge for standardizing on PSR-17 with Diactoros.
composer require <vendor>/<package> and then immediately run composer show <vendor>/<package> --all — confirm which psr/http-factory constraint actually resolved on your PHP version.RequestFactoryInterface, ResponseFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, UriFactoryInterface, ServerRequestFactoryInterface). If those aren't bound, the package is a library you wire up yourself; if they are, you get constructor injection for free.php artisan vendor:publish --tag=...) or whether the package is deliberately zero-config.Http::withHeaders(...)->post(...), a service that takes RequestFactoryInterface + StreamFactoryInterface + a PSR-18 ClientInterface can build the request itself and stay portable — which is exactly the point of depending on psr/http-factory rather than on Guzzle or Laravel's HTTP client.The 1.0.0 tag matters here: a first stable release signals the public API is now semver-frozen. If you were already on 0.x, budget a short pass over your own call sites before bumping, and pin with ^1.0 rather than a wide-open constraint.
Bind interfaces, not the implementation. In AppServiceProvider::register(), alias the package's concrete factories to the PSR-17 interfaces so every downstream consumer resolves the same instance type:
$this->app->bind(RequestFactoryInterface::class, fn ($app) => $app->make(YourRequestFactory::class));
Do this once, in one provider. Scattering concrete factory references through domain code defeats the reason you installed the package.
Constructor injection in services and jobs. Jobs are serialized, so inject the factory into the job's handle() method signature (or resolve from the container inside handle) rather than storing it as a constructor property.
Contextual binding for multi-client setups. If two integrations need differently configured factories (different base URIs, different stream temp dirs), use when(ClientA::class)->needs(...)->give(...) instead of building a factory-per-call inside business logic.
Feature tests: swap the binding for a spy that records what was asked for, then assert on the recorded calls. Because PSR-17 is interface-only, you can substitute any implementation — including the package's own when you're asserting on concrete message behaviour, and a hand-rolled fake when you only care about the call shape.
Package authors: depend on psr/http-factory in require (not require-dev) and type-hint the interfaces in your public constructors. Never type-hint the concrete factory — that's what forces consumers onto a specific implementation.
Bridge to Laravel's HTTP client where you need it: build the request via PSR-17, then hand the PSR-7 message to whatever transport you use, rather than mixing both APIs in the same method.
$request->withHeader(...) returns a new instance; discarding the return value is the single most common silent bug in this space. Reassign every time, or use a fluent chain that ends in a variable.withBody() wants a StreamInterface, not a string. Route strings through StreamFactoryInterface::createStream() first, and remember createStream() leaves the pointer at the start while streams created from a file may need an explicit rewind().queue:work) can leak state between requests. Prefer immutable config passed to the constructor.BindingResolutionException for RequestFactoryInterface almost always means the provider wasn't registered (check bootstrap/providers.php / package discovery) or was registered after the consumer.php artisan config:clear; this eats an hour on first integration more often than any code bug.UploadedFile. UploadedFileFactoryInterface is for constructing PSR-7 uploads in tests and non-HTTP contexts; request validation still belongs to Laravel's Illuminate\Http\UploadedFile.^1.0 is correct for a library so consumers aren't forced into a single patch of a standards package. If the package pins an exact 1.0 you can't control, raise it upstream — exact pins on PSR packages cause real dependency-resolution conflicts.StreamFactoryInterface and leave the package's classes untouched — that keeps your customisation isolated and upgrade-safe.@var docblocks or thin wrapper methods in your own code; otherwise static analysis can't tell you that getBody() returns a seekable stream.How can I help you explore Laravel packages today?