graham-campbell/guzzle-factory
Simple factory for creating Guzzle HTTP clients with sensible defaults. Configure options like base_uri and get a ready-to-use client in one call. Supports PHP 7.4–8.5 and integrates cleanly into modern PHP projects.
Installation:
composer require graham-campbell/guzzle-factory
Add to composer.json if using Laravel’s autoloader or register the service provider in config/app.php if needed (though this package is framework-agnostic).
First Use Case: Create a client with a base URI in a Laravel service or controller:
use GrahamCampbell\GuzzleFactory\GuzzleFactory;
$client = GuzzleFactory::make(['base_uri' => 'https://api.example.com']);
Where to Look First:
src/GuzzleFactory.php for method signatures and defaults (e.g., retry logic, TLS settings).Centralized Client Creation:
Define clients in a dedicated service class (e.g., app/Services/HttpClientService.php) to avoid repetition:
class HttpClientService
{
public function createPaymentClient(): ClientInterface
{
return GuzzleFactory::make([
'base_uri' => config('services.stripe.base_uri'),
'timeout' => 30,
'headers' => ['Authorization' => 'Bearer ' . config('services.stripe.key')],
]);
}
}
Dependency Injection in Laravel: Bind the factory to the service container for easy access:
// In a service provider (e.g., AppServiceProvider)
$this->app->singleton('guzzle.factory', function () {
return new GuzzleFactory();
});
Then inject it into controllers/services:
public function __construct(private GuzzleFactory $guzzleFactory) {}
Dynamic Configuration: Use Laravel’s config or environment variables to customize clients:
$client = GuzzleFactory::make([
'base_uri' => env('API_BASE_URL'),
'timeout' => env('API_TIMEOUT', 10),
'retries' => [
'total' => env('API_RETRIES', 3),
'backoff' => 200, // ms
],
]);
Handler Stack Customization:
For advanced use cases (e.g., custom middleware), use the getHandlerStack method:
$stack = GuzzleFactory::getHandlerStack();
$stack->push(Middleware::tap(...));
$client = new Client(['handler' => $stack]);
Retry Policies: Leverage built-in retry logic for transient failures (e.g., 429, 5xx):
$client = GuzzleFactory::make([
'base_uri' => 'https://api.example.com',
'retry' => [
'enabled' => true,
'total' => 5,
'backoff' => 300, // ms
'except' => [401, 403], // Skip retries for auth errors
],
]);
Testing: Mock the factory in unit tests to isolate HTTP logic:
$mockClient = Mockery::mock(ClientInterface::class);
$mockFactory = Mockery::mock(GuzzleFactory::class);
$mockFactory->shouldReceive('make')->andReturn($mockClient);
$this->app->instance(GuzzleFactory::class, $mockFactory);
API Integration Workflow:
config/services.php:
'stripe' => [
'base_uri' => 'https://api.stripe.com/v1',
'timeout' => 30,
],
class StripeService
{
public function __construct(private GuzzleFactory $guzzleFactory) {}
public function createCustomer(array $data): array
{
$client = $this->guzzleFactory->make(config('services.stripe'));
$response = $client->post('/customers', ['json' => $data]);
return json_decode($response->getBody(), true);
}
}
Modular Architecture: Use the factory in Laravel packages or modules to ensure consistency across teams:
// In a package's service provider
$this->app->bind('package.http-client', function () {
return GuzzleFactory::make([
'base_uri' => 'https://package-api.example.com',
'timeout' => 15,
]);
});
Background Jobs: Pass clients to Laravel jobs for async processing:
class ProcessPaymentJob implements ShouldQueue
{
public function __construct(private GuzzleFactory $guzzleFactory) {}
public function handle()
{
$client = $guzzleFactory->make(config('services.payment-gateway'));
// Process payment...
}
}
Laravel Configuration:
Store default options in config/services.php and override them per client:
'guzzle' => [
'defaults' => [
'timeout' => 10,
'retries' => ['total' => 3],
],
],
Then merge them in your factory call:
$client = GuzzleFactory::make(array_merge(
config('guzzle.defaults'),
['base_uri' => 'https://custom-api.example.com']
));
Environment-Specific Configs:
Use Laravel’s env() or .env files to switch between dev/staging/prod:
$client = GuzzleFactory::make([
'base_uri' => env('API_URL', 'https://api.example.com'),
'debug' => app()->environment('local'),
]);
Middleware Integration: Add custom middleware to the handler stack for logging, auth, or transformation:
$stack = GuzzleFactory::getHandlerStack();
$stack->push(
Middleware::tap(function (RequestOptions $options) {
$options['headers']['X-Custom-Header'] = 'value';
})
);
$client = new Client(['handler' => $stack]);
Caching Clients: For performance, cache clients in Laravel’s cache or use a singleton pattern:
$client = Cache::remember('stripe_client', now()->addHours(1), function () {
return GuzzleFactory::make(config('services.stripe'));
});
TLS Version Enforcement:
cURL error 35 (SSL connect errors) or Guzzle\Exception\ConnectException in logs.Retry Logic Quirks:
429, 5xx, and customizable 4xx codes (see retry.except).base_uri is dynamic (e.g., load-balanced endpoints). Ensure the URI is stable during retries.GET requests) to avoid unnecessary calls:
'retry' => ['enabled' => false],
Handler Stack Overrides:
$stack = GuzzleFactory::getHandlerStack();
// Add custom middleware...
$client = new Client(['handler' => $stack]);
PHP Version Mismatches:
FatalError or RuntimeException during installation/composer update.Base URI Validation:
base_uri must be a valid URL (e.g., https://example.com). Relative paths or malformed URIs will throw exceptions.$baseUri = filter_var(config('services
How can I help you explore Laravel packages today?