PSR-17: HTTP Factories
Also Known As
PSR-17
HTTP factories PSR
RequestFactoryInterface
TL;DR
Standard factory interfaces for creating PSR-7 HTTP objects — decoupling library code from any specific PSR-7 implementation.
Explanation
PSR-17 provides factory interfaces for every PSR-7 type: RequestFactoryInterface, ResponseFactoryInterface, ServerRequestFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, and UriFactoryInterface. By accepting a PSR-17 factory rather than hard-coding new GuzzleHttp\Psr7\Response(), library code works with any PSR-7 implementation. Particularly valuable in middleware and framework internals that construct HTTP messages. Implementations include nyholm/psr7 (fastest, smallest) and guzzlehttp/psr7. PSR-17 completes the HTTP abstraction layer begun by PSR-7 and extended by PSR-15.
Common Misconception
✗ PSR-17 is an extension of PSR-7. PSR-17 is a companion standard that defines factory interfaces for creating PSR-7 objects — without PSR-17, libraries that need to create request/response objects had to depend on specific PSR-7 implementations rather than an abstract factory.
Why It Matters
PSR-17 defines HTTP message factory interfaces — code that uses RequestFactoryInterface and ResponseFactoryInterface can create HTTP objects without depending on a specific PSR-7 implementation.
Common Mistakes
- Instantiating PSR-7 objects directly (new GuzzleHttp\Psr7\Request()) — tightly couples to one library.
- Not injecting factories — hardcoded factory calls prevent swapping PSR-7 implementations.
- Confusing PSR-7 (HTTP message interfaces) with PSR-17 (factory interfaces for creating them).
- Not using a discovery package — manually resolving which factory implementation is installed.
Code Examples
✗ Vulnerable
// Direct PSR-7 instantiation — coupled to Guzzle:
$request = new GuzzleHttp\Psr7\Request('GET', $url);
// PSR-17 factory — implementation-agnostic:
public function __construct(private RequestFactoryInterface $factory) {}
$request = $this->factory->createRequest('GET', $url);
// Swap Guzzle for Nyholm PSR-7 by changing one DI binding
✓ Fixed
// PSR-17 HTTP Factories — create PSR-7 message objects
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UriFactoryInterface;
// Inject factories rather than instantiating directly
class OrderController {
public function __construct(
private ResponseFactoryInterface \$responseFactory,
private StreamFactoryInterface \$streamFactory,
) {}
public function show(int \$id): ResponseInterface {
\$order = Order::findOrFail(\$id);
\$body = \$this->streamFactory->createStream(json_encode(\$order));
return \$this->responseFactory->createResponse(200)
->withHeader('Content-Type', 'application/json')
->withBody(\$body);
}
}
// Implementations: nyholm/psr7, guzzlehttp/psr7, laminas-diactoros
References
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
12
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 5
ChatGPT 2
Perplexity 1
Google 1
Ahrefs 1
Also referenced
How they use it
crawler 9
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟢 Low
⚙ Fix effort: Low
⚡ Quick Fix
Inject PSR-17 factories (RequestFactoryInterface, ResponseFactoryInterface) instead of instantiating concrete HTTP classes — this makes your code testable and framework-agnostic
📦 Applies To
PHP 7.1+
web
api
cli
🔗 Prerequisites
🔍 Detection Hints
new GuzzleHttp\Psr7\Response() directly instead of ResponseFactoryInterface; framework-specific HTTP object creation preventing portability
Auto-detectable:
✓ Yes
phpstan
deptrac
⚠ Related Problems
🤖 AI Agent
Confidence: Low
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File