PSR-7: HTTP Message Interface
Also Known As
PSR-7
PSR-7 HTTP messages
ServerRequestInterface
ResponseInterface
TL;DR
Immutable interfaces for HTTP requests and responses, enabling framework-agnostic HTTP handling and middleware composition.
Explanation
PSR-7 defines interfaces for HTTP messages: RequestInterface, ServerRequestInterface (incoming requests with parsed body, cookies, uploaded files), ResponseInterface, and supporting types (UriInterface, StreamInterface, UploadedFileInterface). All PSR-7 objects are immutable — methods that modify state return new instances (withHeader(), withBody()). This enables safe middleware pipelines where each layer receives and returns message objects. Implementations include Guzzle PSR-7, Nyholm PSR-7 (lightest), and Laminas Diactoros. PSR-7 is the foundation of PSR-15 middleware.
Common Misconception
✗ PSR-7 request objects represent the mutable current HTTP request. PSR-7 objects are immutable — withHeader(), withBody() etc. return new instances rather than modifying in place. This prevents action-at-a-distance bugs where middleware modifications unexpectedly affect other handlers.
Why It Matters
PSR-7 defines immutable HTTP message interfaces — components that accept ServerRequestInterface and ResponseInterface work with any PSR-7 implementation, enabling middleware and handler interoperability.
Common Mistakes
- Not using the return value of withHeader(), withBody(), etc — PSR-7 messages are immutable; modifications return new instances.
- Type-hinting against concrete classes (GuzzleHttp\Psr7\Request) instead of the PSR-7 interfaces.
- Forgetting that getQueryParams() returns parsed query params but getParsedBody() returns POST data — different methods.
- Not using a PSR-17 factory to create PSR-7 objects — direct instantiation couples to one library.
Code Examples
✗ Vulnerable
// Mutating immutable PSR-7 object — original unchanged:
$response->withHeader('Content-Type', 'application/json'); // Returns new instance!
// $response is unchanged — the new instance is discarded
// Correct:
$response = $response->withHeader('Content-Type', 'application/json');
return $response->withBody($stream);
✓ Fixed
// PSR-7 — immutable HTTP message objects
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
// All mutating methods return NEW instances — original unchanged
function addJsonHeader(ResponseInterface \$response): ResponseInterface {
return \$response->withHeader('Content-Type', 'application/json');
// ^^ returns new object with header added
}
// Read request data
public function handle(ServerRequestInterface \$request): ResponseInterface {
\$body = (string) \$request->getBody();
\$data = json_decode(\$body, true);
\$userId = \$request->getAttribute('user_id');
\$query = \$request->getQueryParams();
\$cookies = \$request->getCookieParams();
}
References
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
18
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 8
Perplexity 3
ChatGPT 2
Google 1
Ahrefs 1
Also referenced
How they use it
crawler 14
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: Medium
⚡ Quick Fix
Program against PSR-7 interfaces (RequestInterface, ResponseInterface) not concrete implementations — this lets you swap Guzzle for Symfony HttpClient or use any PSR-7 compliant library
📦 Applies To
PHP 5.3+
web
api
cli
🔗 Prerequisites
🔍 Detection Hints
Direct use of Guzzle or Symfony specific request objects instead of PSR-7 interfaces; framework-specific request object in business logic
Auto-detectable:
✓ Yes
phpstan
deptrac
⚠ Related Problems
🤖 AI Agent
Confidence: Low
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File