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

Http Client Implementations Laravel Package

psr-discovery/http-client-implementations

Discovers an installed PSR-18 HTTP client at runtime by checking for well-known implementations and returning the first available instance. Ideal for SDKs/libraries to support PSR-18 without hard dependencies or extra user configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package in your Laravel project:
    composer require psr-discovery/http-client-implementations
    
  2. Ensure a PSR-18 HTTP client implementation is installed (e.g., Guzzle, Symfony HTTP Client, or others listed in the package). Example:
    composer require guzzlehttp/guzzle
    
  3. First use case: Instantiating a client in a service or controller:
    use PsrDiscovery\Discover;
    use Psr\Http\Message\RequestFactoryInterface;
    
    $httpClient = Discover::httpClient();
    $requestFactory = Discover::httpMessageFactory(); // Optional: If using PSR-17
    

Key Files to Review

  • config/app.php: Ensure no conflicting HTTP client bindings exist (e.g., in bindings).
  • composer.json: Verify installed HTTP client implementations (e.g., guzzlehttp/guzzle).
  • Service Providers: Check for manual HTTP client bindings (e.g., HttpClient::macro()).

Implementation Patterns

1. Service Container Integration

Leverage Laravel’s service container to bind the discovered client as a singleton for reuse:

// In a service provider (e.g., AppServiceProvider)
use PsrDiscovery\Discover;
use Psr\Http\Client\ClientInterface;

public function register()
{
    $this->app->singleton(ClientInterface::class, function () {
        return Discover::httpClient(singleton: true);
    });
}

Usage in Controllers/Services:

use Psr\Http\Client\ClientInterface;

public function __construct(private ClientInterface $httpClient) {}

2. Dynamic Client Selection

Use prefer() or use() to enforce specific implementations (e.g., for testing or environment-specific needs):

// Prefer Guzzle in production, mock in tests
if (app()->environment('testing')) {
    Discover\Implementations\Psr18\Clients::use('php-http/mock-client');
} else {
    Discover\Implementations\Psr18\Clients::prefer('guzzlehttp/guzzle');
}

3. Request Factories (PSR-17)

Pair with psr-discovery/http-factory-implementations for request/response factories:

use PsrDiscovery\Discover;
use Psr\Http\Message\RequestFactoryInterface;

$requestFactory = Discover::httpMessageFactory();
$request = $requestFactory->createRequest('GET', 'https://api.example.com');
$response = $httpClient->sendRequest($request);

4. Middleware Integration

Attach middleware to the discovered client (e.g., logging, retries):

use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

$httpClient = Discover::httpClient();
$httpClient = new class($httpClient) implements ClientInterface {
    public function __construct(private ClientInterface $client) {}

    public function sendRequest(RequestInterface $request): ResponseInterface {
        // Pre-process request (e.g., add headers)
        $response = $this->client->sendRequest($request);
        // Post-process response
        return $response;
    }
};

5. Testing Patterns

Prioritize mock clients in tests:

// In phpunit.xml or setupTests()
Discover\Implementations\Psr18\Clients::use('php-http/mock-client');

// Test example
$mockClient = Discover::httpClient();
$mockClient->expects($this->once())
           ->method('sendRequest')
           ->willReturn($this->createMock(ResponseInterface::class));

Gotchas and Tips

Pitfalls

  1. Null Returns:

    • If no compatible client is found, Discover::httpClient() returns null. Always check:
      $client = Discover::httpClient() ?: throw new RuntimeException('No HTTP client found');
      
    • Fix: Ensure at least one supported client (e.g., Guzzle) is installed.
  2. Singleton Conflicts:

    • Reusing the same client instance across requests may cause issues with stateful middleware (e.g., auth tokens). Use singleton: false if needed:
      $client = Discover::httpClient(singleton: false);
      
  3. Version Mismatches:

    • The package supports specific versions of clients (e.g., Guzzle ^7.0 | ^8.0). Installing incompatible versions may break discovery.
    • Debug Tip: Check composer why guzzlehttp/guzzle to verify installed version.
  4. Mocking Priority:

    • Mock clients (e.g., php-http/mock-client) are prioritized over real clients. To bypass this:
      Discover\Implementations\Psr18\Clients::use('guzzlehttp/guzzle');
      

Debugging Tips

  • Verify Discovery: Inspect the discovery logic by checking the PsrDiscovery\Implementations\Psr18\Clients class for supported packages.
    var_dump(Discover\Implementations\Psr18\Clients::getAvailable());
    
  • Logging: Add debug logs to trace discovery failures:
    $client = Discover::httpClient();
    if (!$client) {
        \Log::error('No PSR-18 client found. Available packages: ' . implode(', ', array_keys(Discover\Implementations\Psr18\Clients::getAvailable())));
    }
    

Extension Points

  1. Custom Implementations: Extend the package to support additional clients by modifying the PsrDiscovery\Implementations\Psr18\Clients class or creating a custom discovery strategy:

    // Example: Add a custom client
    Discover\Implementations\Psr18\Clients::add('my/custom-client', MyCustomClient::class);
    
  2. Environment-Specific Config: Use Laravel’s config to override client preferences:

    // config/http-client.php
    return [
        'preferred_client' => env('HTTP_CLIENT', 'guzzlehttp/guzzle'),
    ];
    

    Then integrate in a service provider:

    Discover\Implementations\Psr18\Clients::prefer(config('http-client.preferred_client'));
    
  3. Fallback Logic: Implement a fallback chain for critical paths:

    $client = Discover::httpClient() ?: new \GuzzleHttp\Client();
    

Performance Considerations

  • Singleton Caching: Enable singleton: true to avoid redundant instantiation in high-traffic applications.
  • Lazy Loading: Defer client discovery until first use to reduce bootstrap time:
    $client = fn() => Discover::httpClient(singleton: true);
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky