sunrise/http-message
Sunrise HTTP Message provides a PSR-7 HTTP message implementation with PSR-17 factories, aligned with RFC-7230. Use it to create and work with requests, responses, URIs, streams, and uploaded files in a standards-compliant way.
Installation:
composer require sunrise/http-message
Ensure your composer.json has PHP ≥7.4 (recommended: 8.1+).
First Use Case: Create a PSR-7 request/response with built-in factories:
use Sunrise\HttpMessage\{RequestFactory, ResponseFactory};
$request = RequestFactory::createJsonRequest('GET', '/api/users', ['id' => 1]);
$response = ResponseFactory::createJsonResponse(['status' => 'success']);
Key Classes to Explore:
RequestFactory/ResponseFactory: Convenience methods for common HTTP types (JSON, HTML, URL-encoded).Stream: Core stream handling (e.g., writeStream(), LineStream).FileStream: For file uploads/downloads (check getFilename()).Documentation: Start with Sunrise’s official docs for API references and examples.
$request = RequestFactory::createJsonRequest('POST', '/data', ['key' => 'value']);
$response = ResponseFactory::createJsonResponse($data, 201);
$request = RequestFactory::createUrlEncodedRequest('POST', '/login', [
'email' => 'user@example.com',
'password' => 'secret'
]);
$fileStream = new FileStream('/path/to/file.txt');
$request = RequestFactory::createRequest('POST', '/upload')
->withBody($fileStream);
$stream = new Stream();
$stream->writeStream($sourceStream, 1024); // Write in 1KB chunks
Use with Laravel’s middleware pipeline (e.g., HandlePsr7Request):
use Sunrise\HttpMessage\{RequestInterface, ResponseInterface};
public function handle(RequestInterface $request, Closure $next): ResponseInterface {
// Modify request/response
return $next($request)->withHeader('X-Processed', 'true');
}
Register factories in Laravel’s AppServiceProvider:
public function register(): void {
$this->app->singleton(RequestFactory::class, fn() => new RequestFactory());
$this->app->singleton(ResponseFactory::class, fn() => new ResponseFactory());
}
Mock requests/responses in PHPUnit:
$mockRequest = $this->createMock(RequestInterface::class);
$mockRequest->method('getMethod')->willReturn('GET');
Illuminate\Http\Request:
Extend Sunrise\HttpMessage\Request for custom logic:
class CustomRequest extends Request {
public function getCustomHeader(): string {
return $this->getHeaderLine('X-Custom');
}
}
Psr7Middleware facade to wrap Laravel middleware:
use Sunrise\HttpMessage\Psr7Middleware;
$middleware = Psr7Middleware::wrap($laravelMiddleware);
LineStream for large text files to process line-by-line:
$lineStream = new LineStream($fileStream);
foreach ($lineStream as $line) {
// Process line
}
RequestFactory/ResponseFactory for domain-specific defaults:
class ApiRequestFactory extends RequestFactory {
public function createAuthRequest(string $method, string $uri, array $data): RequestInterface {
return $this->createRequest($method, $uri)
->withHeader('Authorization', 'Bearer token')
->withBody($this->createJsonBody($data));
}
}
getHeader()/getHeaderLine() may return original casing.withAddedHeader() for consistency:
$request->withAddedHeader('content-type', 'application/json'); // Normalized
detach()) cannot be reused. Always clone or reattach:
$stream = $request->getBody();
$clonedStream = clone $stream; // Safe to use later
sunrise/http-header to ^3.0 if issues arise.createJsonResponse() throws JsonException on invalid data. Validate early:
try {
$response = ResponseFactory::createJsonResponse($data);
} catch (JsonException $e) {
abort(500, 'Invalid JSON data');
}
getFilename() only works for local files. For uploaded files, use:
$file = $request->getUploadedFile('file');
$stream = new FileStream($file->getPathname());
Dump raw headers for debugging:
dd($request->getHeaders());
Read stream contents without consuming it:
$stream = $request->getBody();
$contents = $stream->getContents(); // Consumes stream!
// Alternative (non-consuming):
$stream->rewind();
$chunk = $stream->read(1024);
Log PSR-7 requests/responses:
public function handle(RequestInterface $request, Closure $next): ResponseInterface {
\Log::debug('Request:', [
'method' => $request->getMethod(),
'uri' => (string) $request->getUri(),
'headers' => $request->getHeaders()
]);
return $next($request);
}
Implement StreamInterface for domain-specific streams (e.g., database blobs):
class DatabaseStream implements StreamInterface {
public function read(int $length): string {
return $this->db->fetchBlob($length);
}
// ... other methods
}
Decorate factories to add pre-processing:
class AuthRequestFactory {
public function __construct(private RequestFactory $factory) {}
public function create(string $method, string $uri): RequestInterface {
return $this->factory->createRequest($method, $uri)
->withHeader('X-Auth', 'required');
}
}
Create reusable middleware for PSR-7:
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class LoggingMiddleware implements MiddlewareInterface {
public function process(RequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
// Pre-flight logic
$response = $handler->handle($request);
// Post-flight logic
return $response;
}
}
Combine with sunrise/uri for advanced URI manipulation:
use Sunrise\Uri\Uri;
$uri = Uri::createFromString('/api/users?page=1');
$request = RequestFactory::createRequest('GET', $uri);
RequestFactory:
$factory = new RequestFactory();
$factory->setDefaultHttpVersion('1.1');
sunrise/http-header config (if integrated):
$headerManager = new HeaderManager();
$headerManager->setCaseInsensitive(true);
How can I help you explore Laravel packages today?