Installation:
composer require kriswallsmith/buzz
Buzz is dependency-free and requires PHP 7.4+.
First Request:
use Buzz\Browser;
use Buzz\Message\Request;
$client = new Browser();
$request = new Request('GET', 'https://api.example.com/users');
$response = $client->send($request);
echo $response->getBody();
Key Classes:
Browser: Main client for sending requests.Request: Construct HTTP requests (GET, POST, etc.).Message\Response: Handle responses (status, headers, body).First Use Case: Fetch JSON data from an API:
$response = $client->sendRequest('GET', 'https://api.example.com/data');
$data = json_decode($response->getBody(), true);
Pattern: Use sendRequest() for simplicity or Request/Response objects for control.
// Simple GET
$response = $client->sendRequest('GET', 'https://api.example.com/users');
// POST with JSON body
$request = new Request('POST', 'https://api.example.com/users');
$request->setBody(json_encode(['name' => 'John']));
$request->setHeader('Content-Type', 'application/json');
$response = $client->send($request);
Laravel Integration: Use a service class to wrap Buzz for consistency:
class ApiClient {
protected $client;
public function __construct(Browser $client) {
$this->client = $client;
}
public function getUsers() {
return $this->client->sendRequest('GET', config('services.api.users'));
}
}
Pattern: Check status codes and parse responses:
$response = $client->sendRequest('GET', 'https://api.example.com/data');
if ($response->getStatusCode() === 200) {
return json_decode($response->getBody(), true);
}
throw new \RuntimeException('API request failed');
Laravel HTTP Client Wrapper:
Extend Laravel’s Http client to use Buzz for specific endpoints:
$response = Http::withOptions(['handler' => $buzzHandler])->get('https://external-api.com');
Pattern: Add headers for auth (e.g., Bearer tokens):
$request = new Request('GET', 'https://api.example.com/protected');
$request->setHeader('Authorization', 'Bearer ' . $token);
Laravel Auth Integration: Use middleware to inject auth headers:
$request->setHeader('Authorization', 'Bearer ' . auth()->token());
$maxRetries = 3;
for ($i = 0; $i < $maxRetries; $i++) {
$response = $client->sendRequest('GET', 'https://api.example.com/data');
if ($response->getStatusCode() < 500) break;
sleep(2 ** $i); // Exponential backoff
}
$response = $client->sendRequest('GET', 'https://example.com/large-file.zip');
file_put_contents('large-file.zip', $response->getBody());
Laravel Service Providers:
Bind Buzz’s Browser to the container for dependency injection:
$this->app->singleton(Browser::class, function () {
return new Browser();
});
Configurable Base URLs:
Store API endpoints in config/services.php:
'api' => [
'base_url' => env('API_BASE_URL'),
'timeout' => 30,
],
Then use them in your service class:
$response = $client->sendRequest('GET', config('services.api.base_url') . '/users');
Mocking for Tests:
Use Buzz’s MockHandler to simulate responses:
use Buzz\Message\Response;
use Buzz\MockHandler;
$mock = new MockHandler();
$mock->setDefaultResponse(new Response(200, [], '{"test": true}'));
$client = new Browser();
$client->setHandler($mock);
$response = $client->sendRequest('GET', 'https://fake-api.com');
Middleware for Requests: Create a middleware to modify requests (e.g., add headers):
class AddHeadersMiddleware {
public function __invoke(Request $request) {
$request->setHeader('X-Custom-Header', 'value');
return $request;
}
}
Apply it before sending:
$request = (new AddHeadersMiddleware())($request);
$client->send($request);
Connection Timeouts:
$client = new Browser();
$client->setTimeout(10); // 10 seconds
Http::timeout() for Laravel’s HTTP client if wrapping Buzz.Redirect Handling:
$client->setFollowRedirects(false);
Response::getEffectiveUrl() to see where a request redirected.SSL/TLS Issues:
stream_context_create for SSL. If you encounter issues:
$context = stream_context_create([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
]
]);
$client->setHandler(new \Buzz\Handler\CurlHandler($context));
Memory Leaks with Large Responses:
$response = $client->sendRequest('GET', 'https://example.com/large-file');
$stream = fopen('file.zip', 'w');
fwrite($stream, $response->getBody());
fclose($stream);
Case-Sensitive Headers:
$request->setHeader('content-type', 'application/json');
Log Requests/Responses:
$handler = new class extends \Buzz\Handler\CurlHandler {
public function send(Request $request) {
\Log::debug('Request:', [
'url' => $request->getUrl(),
'method' => $request->getMethod(),
'headers' => $request->getHeaders(),
]);
return parent::send($request);
}
};
$client->setHandler($handler);
Inspect Raw Responses:
\Log::debug('Raw Response:', $response->getBody());
Handle Malformed JSON:
$body = $response->getBody();
json_decode($body); // Throws exception if invalid
Custom Handlers:
Buzz\Handler\HandlerInterface for custom logic (e.g., proxy support):
class ProxyHandler implements HandlerInterface {
public function send(Request $request) {
// Add proxy logic here
return new Response(200, [], 'Proxy response');
}
}
$client->setHandler(new ProxyHandler());
Event Dispatching:
$client->on('request', function (Request $request) {
\Log::info('Request sent', ['url' => $request->getUrl()]);
});
Response Transformers:
$response = $client->sendRequest('GET', 'https://api.example.com/data');
$data = (new JsonTransformer())->transform($response);
Retry Middleware:
How can I help you explore Laravel packages today?