← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

PSR-7: HTTP Message Interface

Style PHP 5.3+ Intermediate
debt(d5/e5/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5), phpstan and deptrac can detect concrete class type-hints instead of PSR-7 interfaces, and the immutability misuse (ignoring return of withHeader) is catchable by static analysis but often slips past defaults.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor' (e5), swapping concrete request/response classes for PSR-7 interfaces and introducing PSR-17 factories typically requires changes across controllers, middleware, and DI configuration in one component.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5), PSR-7 applies across web/api/cli contexts and shapes how middleware, handlers, and HTTP plumbing are written throughout the app; immutability discipline is an ongoing tax but not architecture-defining since it's an interop standard.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7), the misconception that PSR-7 objects are mutable contradicts how most framework request objects work elsewhere — $request->withHeader() silently does nothing if you don't capture the return value, a behaviour opposite to typical PHP object semantics.

About DEBT scoring →

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();
}

Tags


Added 15 Mar 2026
Edited 22 Mar 2026
Views 92
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 2 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 2 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S
No pings yet today
No pings yesterday
Amazonbot 14 PetalBot 12 ChatGPT 7 Ahrefs 7 SEMrush 6 Google 4 Perplexity 3 Bing 3 Applebot 3 Scrapy 2 Twitter/X 2 Claude 1 Meta AI 1
crawler 60 crawler_json 5
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


✓ schema.org compliant