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 Contracts Laravel Package

symfony/http-client-contracts

Symfony HttpClient Contracts provides stable interfaces for HTTP clients and responses, extracted from Symfony. Build libraries against these battle-tested abstractions and swap implementations easily while staying compatible with Symfony’s HttpClient ecosystem.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer:

composer require symfony/http-client-contracts

This package provides only interfaces—no implementations. Pair it with a concrete HTTP client like:

  • symfony/http-client (recommended for async, HTTP/2, and pooling)
  • guzzlehttp/guzzle (via guzzlehttp/psr7 or php-http/guzzle7-adapter)
  • php-http/client (auto-discovers installed clients)

First use case: Inject HttpClientInterface into a service and type-hint against it:

use Symfony\Contracts\HttpClient\HttpClientInterface;

class ApiService
{
    public function __construct(private HttpClientInterface $client) {}

    public function fetchData(string $endpoint): array
    {
        $response = $this->client->request('GET', $endpoint);
        return $response->toArray(); // Parses JSON response
    }
}

Key first step: Always depend on HttpClientInterface, not concrete implementations. This enables swapping clients (e.g., for testing or production).


Implementation Patterns

Dependency Injection in Laravel

Register the interface in config/services.php:

'http_client' => [
    'default' => Symfony\Contracts\HttpClient\HttpClientInterface::class,
],

Bind a concrete client (e.g., Symfony’s HttpClient) in a service provider:

$this->app->bind(
    Symfony\Contracts\HttpClient\HttpClientInterface::class,
    fn () => new Symfony\Component\HttpClient\HttpClient()
);

Testing Workflows

  • Unit tests: Mock HttpClientInterface with MockResponse:
    $mockResponse = MockResponse::fromJsonString('{"status": "ok"}');
    $mockClient = new MockHttpClient([$mockResponse]);
    $service = new ApiService($mockClient);
    
  • Integration tests: Use TestHttpClient (from symfony/http-client) to verify requests:
    $client = new TestHttpClient();
    $client->request('GET', 'https://api.example.com/data')
           ->toArray();
    $this->assertCount(1, $client->getRequests());
    

Response Handling

  • Error handling: Check status codes before processing:
    $response = $client->request('GET', $url);
    if ($response->getStatusCode() >= 400) {
        throw new RuntimeException('API request failed');
    }
    
  • Async support: Use AsyncHttpClient (from symfony/http-client) for non-blocking calls:
    $asyncClient = new AsyncHttpClient();
    $promise = $asyncClient->request('GET', $url);
    $response = $promise->await();
    

Decorator Pattern

Wrap the client to add cross-cutting concerns (e.g., logging, retries):

class RetryHttpClient implements HttpClientInterface
{
    public function __construct(private HttpClientInterface $client) {}

    public function request(string $method, string $url, array $options = []): ResponseInterface
    {
        try {
            return $this->client->request($method, $url, $options);
        } catch (TransportException $e) {
            // Retry logic here
            return $this->client->request($method, $url, $options);
        }
    }
}

Gotchas and Tips

Common Pitfalls

  1. Missing concrete client: HttpClientInterface alone won’t work—install a PSR-18-compliant client (e.g., symfony/http-client).
  2. Response parsing errors: toArray() throws on empty bodies. Use toArray(false) to skip JSON decode:
    $response->toArray(false); // Returns `null` for empty responses
    
  3. Async misconceptions: The contract supports async, but basic request() is synchronous. Use AsyncHttpClient for non-blocking calls.

Debugging Tips

  • Enable debug mode in Symfony’s HttpClient:
    # config/packages/http_client.yaml
    framework:
        http_client:
            debug: '%kernel.debug%'
    
  • Inspect requests with TestHttpClient in tests:
    $client = new TestHttpClient();
    $client->request('GET', 'https://api.example.com');
    $this->assertEquals('GET', $client->getRequests()[0]->getMethod());
    

Extension Points

  • Middleware: Decorate the client to add auth, caching, or retries:
    class AuthHttpClient implements HttpClientInterface
    {
        public function __construct(private HttpClientInterface $client) {}
    
        public function request(string $method, string $url, array $options = []): ResponseInterface
        {
            $options['headers']['Authorization'] = 'Bearer ' . $this->token;
            return $this->client->request($method, $url, $options);
        }
    }
    
  • Retry strategies: Use symfony/http-client's retry middleware or implement a custom decorator.

Laravel-Specific Notes

  • Laravel’s Http facade: Not directly compatible. Use HttpClientInterface with a PSR-18 adapter (e.g., php-http/laravel-adapter).
  • PHP 8.1+ required: Laravel 10+ supports this natively. For older versions, use symfony/psr-http-message-bridge to unify PSR-7/18 types.
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope