berlioz/http-message
berlioz/http-message offers PSR-7 compliant HTTP message classes for PHP: immutable requests, responses, URIs, streams, and uploaded files. It works seamlessly with Laravel and other frameworks, giving developers a clean, standards-based foundation for handling HTTP requests and responses.
berlioz/http-message is the pure PSR-7/PSR-17 implementation extracted from the Berlioz framework monorepo (src/Http/Message/). It is architecturally a foundational component: HttpFactory implements all six PSR-17 factory interfaces via traits, and the package ships pluggable body parsers and specialized stream classes. Critically, it has no framework dependencies, so it can be consumed by any PHP 8.2+ codebase — including Laravel, Symfony, or bespoke services — without adopting the rest of Berlioz.
Architecture fit. The package sits in the "standalone components" layer of the Berlioz dependency graph, below Router, Http/Core, and the integration packages. It is a dependency-free leaf, which means adopting it does not drag in the kernel, container, or config system. For a TPM, this is the ideal shape: a narrow, replaceable library that other tiers depend on rather than one that depends on them.
Integration feasibility. Technically trivial: a single Composer requirement, then instantiate HttpFactory wherever PSR-17 factories are expected (PSR-15 middleware, PSR-18 clients, symfony/psr-http-message-bridge). Because it implements interfaces rather than concrete classes, it is swappable with nyholm/psr7, guzzlehttp/psr7, or laminas/laminas-diactoros behind an adapter. The package follows the repo's strict conventions — declare(strict_types=1) everywhere, PSR-12, PSR-4 imports — which lowers code-review friction.
Technical risk. The dominant risk is not code quality but supply chain. One GitHub star and zero dependents means essentially no production validation, no third-party bug reports, and no ecosystem pressure on correctness or performance. Other risks:
with* copy semantics, stream rewinding, chunked bodies, $_FILES upload handling). Without evidence of a large test suite exercising these, parity with an incumbent implementation must be proven, not assumed.CHANGELOG.md before pinning.Key questions.
HttpFactory handle file uploads and server-request creation ($_FILES, $_SERVER) correctly, or is that deferred to Http/Core?nyholm/psr7 and guzzlehttp/psr7 in a hot request loop?Stack fit. Any PHP 8.2+ service. In Laravel specifically, note that the framework's native HTTP layer is Symfony HttpFoundation, not PSR-7; adoption therefore means introducing a PSR-7 boundary (via symfony/psr-http-message-bridge or explicit conversion), which is valuable if the target is PSR-15 middleware, PSR-18 clients, or interoperability with PSR-based libraries. In Symfony, the bridge already exists and HttpFactory can serve as the required PSR-17 factory with a one-line service definition.
Migration path.
composer require berlioz/http-message and pin an exact version in composer.lock.HttpFactory instance in the service container and expose it behind an internal ResponseFactoryInterface-style alias so call sites never reference the concrete namespace.HttpFactory and diff status, headers, and body bytes.Compatibility. PSR-4/7/11/12/14/16/17/18 compliance is claimed and is consistent with the repo-wide standards. Minimum PHP 8.2 aligns with current LTS-era runtimes. The main compatibility question is not interface conformance but behavioral conformance with whichever implementation currently produces your responses — status-line formatting, header casing, default Content-Type, and stream behavior are where silent regressions appear.
Sequencing. Pilot (one service, one boundary) → parity suite green → internal abstraction layer hardened → second service → standardize as the default factory. Do not sequence this as a big-bang replacement of a working HTTP stack; the payoff is interoperability, and the cost of a failed cutover is user-visible response corruption.
Maintenance. MIT license removes legal friction, but the maintenance burden shifts to you. With one maintainer and a monorepo release train, expect to own patches for any bug that blocks you. Budget for either (a) a vendored fork with a documented rebase cadence against upstream tags, or (b) a thin internal adapter so swapping to nyholm/psr7 is a one-file change. The adapter is cheap and is the single highest-value mitigation here.
Support. No vendor, no SLA, no commercial backing. Internal support means naming an owner, writing a one-page runbook, and subscribing to releases on the main Berlioz repo (not the mirror). Community support is effectively absent at one star, so do not plan on upstream responsiveness.
Scaling. PSR-7 immutability means every withHeader/withBody allocates a clone; in hot middleware chains this is measurable but usually acceptable. The real scaling question is streams: confirm whether bodies are memory-backed, and enforce a max-body-size guard at the edge if they are. If the package supports temp-stream bodies, large uploads and downloads are safe; if not, cap payloads at the ingress proxy.
Failure modes.
Ramp-up. The API surface is small and defined by public PSR interfaces, so a PHP developer familiar with PSR-7 needs roughly one day to be productive and two to three days to write meaningful parity tests. Allocate about a week for the team's first integration including the abstraction layer, and treat PSR-7 conformance details (stream rewinding, header normalization) as the actual learning curve — not the Berlioz-specific code.
TPM verdict. Low technical risk, high vendor risk, moderate opportunity. The package is a clean, correctly layered PSR-17 factory that is worth piloting precisely because it is dependency-free and disposable. Approve a bounded pilot behind an internal factory adapter; do not approve it as a strategic dependency until parity tests pass and a fork-and-rebase contingency is documented.
How can I help you explore Laravel packages today?