graham-campbell/guzzle-factory
Simple factory for creating Guzzle HTTP clients with sensible defaults. One-liner client creation via GuzzleFactory::make(), with optional config like base_uri. Supports PHP 7.4–8.5 and integrates cleanly in modern PHP/Laravel apps.
Install the package:
composer require graham-campbell/guzzle-factory
Register the factory in config/app.php under providers:
GrahamCampbell\GuzzleFactory\GuzzleFactoryServiceProvider::class,
Publish the config (optional but recommended for customization):
php artisan vendor:publish --provider="GrahamCampbell\GuzzleFactory\GuzzleFactoryServiceProvider" --tag="config"
This creates config/guzzle-factory.php.
First use case: Create a client in a controller or service:
use GrahamCampbell\GuzzleFactory\Facades\GuzzleFactory;
$client = GuzzleFactory::make(['base_uri' => 'https://api.example.com']);
Edit config/guzzle-factory.php to set:
base_uri (if needed).retry configuration).Example:
'defaults' => [
'timeout' => 30,
'retry' => [
'max_retries' => 3,
'retry_delay' => 100,
],
],
Bind the factory to Laravel’s container in AppServiceProvider@boot() for reusable clients:
public function boot()
{
$this->app->singleton('stripe.client', function () {
return GuzzleFactory::make([
'base_uri' => config('services.stripe.api_url'),
'headers' => ['Authorization' => 'Bearer ' . config('services.stripe.key')],
]);
});
}
Usage in services:
public function __construct(private ClientInterface $stripeClient) {}
Extend the handler stack for cross-cutting concerns (e.g., logging, auth):
use GrahamCampbell\GuzzleFactory\GuzzleFactory;
use GuzzleHttp\HandlerStack;
use GrahamCampbell\GuzzleFactory\Middleware\AuthMiddleware;
$client = GuzzleFactory::make(
['base_uri' => 'https://api.example.com'],
null,
static function (HandlerStack $stack) {
$stack->push(AuthMiddleware::class);
$stack->push(\GuzzleHttp\Middleware::retry(
new \GuzzleHttp\Retry\Middleware(),
new \GuzzleHttp\Retry\RetryConfig()
));
}
);
Centralize API configs in config/services.php:
'stripe' => [
'api_url' => env('STRIPE_API_URL'),
'key' => env('STRIPE_KEY'),
],
Then use it in the factory:
$client = GuzzleFactory::make([
'base_uri' => config('services.stripe.api_url'),
'headers' => ['Authorization' => 'Bearer ' . config('services.stripe.key')],
]);
Use Laravel’s Mockery to stub the factory in tests:
public function test_api_call()
{
$mockClient = Mockery::mock(GuzzleHttp\Client::class);
$mockClient->shouldReceive('get')->andReturn(new \GuzzleHttp\Psr7\Response(200));
$this->app->instance(GuzzleHttp\Client::class, $mockClient);
$result = $this->service->fetchData();
// Assertions...
}
Enable transport sharing for long-lived clients (e.g., in queues or background jobs):
use GrahamCampbell\GuzzleFactory\GuzzleFactory;
use GuzzleHttp\TransportSharing;
$client = GuzzleFactory::make(
['base_uri' => 'https://api.example.com'],
TransportSharing::HANDLER_PREFER // Reuse handlers
);
Combine with Laravel’s Http facade for hybrid usage:
use GrahamCampbell\GuzzleFactory\Facades\GuzzleFactory;
use Illuminate\Support\Facades\Http;
$client = GuzzleFactory::make(['base_uri' => 'https://api.example.com']);
// Use Guzzle directly
$response = $client->get('/endpoint');
// Or wrap in Laravel's Http facade
Http::macro('withGuzzleClient', function ($uri) use ($client) {
return Http::withOptions(['handler' => $client->getConfig('handler')])->get($uri);
});
TLS Version Enforcement:
php.ini:
openssl.cafile=/path/to/cacert.pem
Handler Stack Overrides:
$stack = GuzzleFactory::getHandlerStack();
$stack->push(...);
$client = GuzzleFactory::make([], null, fn (HandlerStack $s) => $s->push(...));
Transport Sharing Trade-offs:
TransportSharing::HANDLER_PREFER improves performance but may cause issues with connection pooling or DNS changes. Use sparingly in long-running processes (e.g., queues).Config File Conflicts:
// config/guzzle-factory.php
'defaults' => ['timeout' => 30],
// Overrides timeout for this client
$client = GuzzleFactory::make(['timeout' => 60]);
PHP 8.1+ Named Arguments:
// ❌ Avoid (may break in future versions)
GuzzleFactory::make([], null, fn (HandlerStack $stack) => $stack->push(...));
// ✅ Prefer explicit order
GuzzleFactory::make([], null, static function (HandlerStack $stack) { ... });
Inspect the Client Config:
Use dd($client->getConfig()) to debug middleware, timeouts, or headers.
Log Handler Stack: Add a debug middleware to log stack contents:
$stack->push(static function (callable $handler) {
return function ($request) use ($handler) {
\Log::debug('Request:', [$request->getUri(), $request->getHeaders()]);
return $handler($request);
};
}, 'debug');
Retry Debugging: Enable Guzzle’s retry logging:
$retryMiddleware = new \GuzzleHttp\Middleware();
$retryMiddleware->setLogger(new \Monolog\Logger('guzzle'));
$stack->push($retryMiddleware);
Transport Sharing Issues:
If you see cURL errors with transport sharing, disable it temporarily:
$client = GuzzleFactory::make([], TransportSharing::DISABLED);
Custom Middleware: Create reusable middleware (e.g., for auth or rate limiting) and push it to the stack:
// app/Http/Middleware/GuzzleAuthMiddleware.php
class GuzzleAuthMiddleware
{
public function __invoke(callable $handler)
{
return function ($request) use ($handler) {
$request = $request->withHeader('Authorization', 'Bearer ' . auth()->token());
return $handler($request);
};
}
}
Usage:
$stack->push(GuzzleAuthMiddleware::class);
Dynamic Config Resolution: Extend the factory to resolve configs from databases or cache:
// app/Providers/GuzzleFactoryServiceProvider.php
public function register()
{
$this->app->extend('guzzle.factory', function ($factory) {
$config = Cache::get('api_config');
return $factory->make($config);
});
}
Event-Driven Extensions:
Listen to Guzzle events (e.g., request, response) via middleware:
$stack->push(static function (callable $handler) {
return function ($request) use ($handler) {
event(new GuzzleRequestEvent($request));
return $handler($request);
};
});
Laravel Events Integration: Trigger Laravel events on Guzzle responses:
$stack->push(static function (callable
How can I help you explore Laravel packages today?