Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Guzzle Factory Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require graham-campbell/guzzle-factory
    
  2. Register the factory in config/app.php under providers:

    GrahamCampbell\GuzzleFactory\GuzzleFactoryServiceProvider::class,
    
  3. Publish the config (optional but recommended for customization):

    php artisan vendor:publish --provider="GrahamCampbell\GuzzleFactory\GuzzleFactoryServiceProvider" --tag="config"
    

    This creates config/guzzle-factory.php.

  4. 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']);
    

Key Configuration

Edit config/guzzle-factory.php to set:

  • Default base_uri (if needed).
  • Retry policies (e.g., retry configuration).
  • Timeout settings.
  • Custom middleware (e.g., auth, logging).

Example:

'defaults' => [
    'timeout' => 30,
    'retry' => [
        'max_retries' => 3,
        'retry_delay' => 100,
    ],
],

Implementation Patterns

1. Service Container Integration

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) {}

2. Middleware Stack Customization

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()
        ));
    }
);

3. Dynamic Configuration via Config Files

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')],
]);

4. Testing with Mocks

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...
}

5. Transport Sharing for Performance

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
);

6. Laravel HTTP Client Wrapper

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);
});

Gotchas and Tips

Pitfalls

  1. TLS Version Enforcement:

    • The package enforces TLS 1.2+ by default (via Guzzle 7.11+). If you hit SSL errors, ensure your server supports TLS 1.2 and update your php.ini:
      openssl.cafile=/path/to/cacert.pem
      
  2. Handler Stack Overrides:

    • Customizing the handler stack replaces defaults. To preserve existing middleware (e.g., retries), clone the stack first:
      $stack = GuzzleFactory::getHandlerStack();
      $stack->push(...);
      $client = GuzzleFactory::make([], null, fn (HandlerStack $s) => $s->push(...));
      
  3. 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).
  4. Config File Conflicts:

    • If you publish the config but also use the factory’s defaults, explicit configs override published ones. Example:
      // config/guzzle-factory.php
      'defaults' => ['timeout' => 30],
      
      // Overrides timeout for this client
      $client = GuzzleFactory::make(['timeout' => 60]);
      
  5. PHP 8.1+ Named Arguments:

    • The factory uses positional arguments for backward compatibility. Avoid relying on named args in custom closures:
      // ❌ Avoid (may break in future versions)
      GuzzleFactory::make([], null, fn (HandlerStack $stack) => $stack->push(...));
      
      // ✅ Prefer explicit order
      GuzzleFactory::make([], null, static function (HandlerStack $stack) { ... });
      

Debugging Tips

  1. Inspect the Client Config: Use dd($client->getConfig()) to debug middleware, timeouts, or headers.

  2. 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');
    
  3. Retry Debugging: Enable Guzzle’s retry logging:

    $retryMiddleware = new \GuzzleHttp\Middleware();
    $retryMiddleware->setLogger(new \Monolog\Logger('guzzle'));
    $stack->push($retryMiddleware);
    
  4. Transport Sharing Issues: If you see cURL errors with transport sharing, disable it temporarily:

    $client = GuzzleFactory::make([], TransportSharing::DISABLED);
    

Extension Points

  1. 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);
    
  2. 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);
        });
    }
    
  3. 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);
        };
    });
    
  4. Laravel Events Integration: Trigger Laravel events on Guzzle responses:

    $stack->push(static function (callable
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony