sabre/http
sabre/http wraps PHP’s HTTP superglobals and output functions into easy-to-mock Request and Response objects. Use it to read input, headers, and body via a consistent API, and to generate responses cleanly in apps and libraries.
Installation:
composer require sabre/http:~5.0.0
Add to composer.json under require.
First Use Case:
use Sabre\HTTP\Sapi;
// Initialize request (run once per request lifecycle)
$request = Sapi::getRequest();
// Initialize response
$response = new Sabre\HTTP\Response();
$response->setStatus(200);
$response->setBody('Hello, World!');
// Send response (run once per request lifecycle)
Sapi::sendResponse($response);
Key Files to Review:
vendor/sabre/http/src/ (Core classes)examples/ (Practical use cases like async clients, reverse proxies)Request Handling:
// Dependency-injected handler
public function handle(Sabre\HTTP\RequestInterface $request) {
$method = $request->getMethod();
$path = $request->getPath();
$data = $request->getPostData();
// Process...
}
Response Construction:
$response = new Sabre\HTTP\Response();
$response->setStatus(201);
$response->setHeader('Content-Type', 'application/json');
$response->setBody(json_encode(['success' => true]));
Middleware Pattern (Decorator-based):
// Auth decorator
class AuthRequestDecorator extends Sabre\HTTP\RequestDecorator {
public function isAuthenticated() {
return $this->getHeader('Authorization') !== null;
}
}
// Usage
$request = new AuthRequestDecorator(Sapi::getRequest());
Laravel Service Provider:
public function register() {
$this->app->singleton(Sabre\HTTP\RequestInterface::class, function() {
return Sapi::getRequest();
});
}
API Client Wrapper:
class ApiClient {
private $client;
public function __construct() {
$this->client = new Sabre\HTTP\Client();
}
public function get(string $url) {
$request = new Sabre\HTTP\Request('GET', $url);
return $this->client->send($request);
}
}
Async Requests:
$client = new Sabre\HTTP\Client();
for ($i = 0; $i < 10; $i++) {
$client->sendAsync(
new Sabre\HTTP\Request('GET', 'https://api.example.com/data'),
function($response) { /* Success */ },
function($error) { /* Error */ }
);
}
$client->wait();
Stream Handling:
getBodyAsString() may only work once (streams are consumed).getBodyAsStream() for repeated access.Header Case Sensitivity:
getHeader()), but case is preserved in storage (setHeader()).POST Data:
setPostData() must be called before getPostData() if you need to modify POST data.Async Client:
wait() to ensure all async requests complete.Response object.Decorator Order:
Inspect Headers:
print_r($request->getHeaders());
Log Request/Response:
$client->on('afterRequest', function($request, $response) {
file_put_contents(
'debug.log',
"Request: {$request->getMethod()} {$request->getUrl()}\n".
"Response: {$response->getStatus()}\n"
);
});
Mocking for Tests:
$mockRequest = $this->createMock(Sabre\HTTP\RequestInterface::class);
$mockRequest->method('getPath')->willReturn('/test');
Custom Request/Response:
class CustomRequest extends Sabre\HTTP\Request {
public function getCustomHeader() {
return $this->getHeader('X-Custom');
}
}
Event Listeners:
Sabre\HTTP\Client with custom events (e.g., beforeRequest for logging).Reverse Proxy:
setBaseUrl() to handle path rewriting:
$request->setBaseUrl('/api/v1');
$subRequest->setUrl('https://backend.example.com' . $request->getPath());
HTTP Version:
setHttpVersion('1.1') if working with HTTP/1.1-specific features.~5.0.0 for PHP 7.4+ or ~4.2.0 for PHP 5.4+.setBody(fopen('file.txt', 'r'))).How can I help you explore Laravel packages today?