- How do I integrate Symfony HttpClient Contracts into an existing Laravel 10+ project?
- Start by installing `symfony/http-client-contracts` and a concrete client like `symfony/http-client` or `guzzlehttp/guzzle`. Bind `HttpClientInterface` in `AppServiceProvider` to your chosen client, then refactor services to inject `HttpClientInterface` instead of Laravel’s `Http` facade. Use adapters like `php-http/guzzle7-adapter` if mixing clients.
- Can I replace Laravel’s Http facade entirely with Symfony’s HttpClientInterface?
- No, not directly. The contracts are interfaces only—you’ll need to refactor facade calls (e.g., `Http::get()`) into services that accept `HttpClientInterface`. For backward compatibility, wrap the interface in a facade or use Laravel’s `Http` facade with a PSR-18 adapter like `guzzlehttp/psr7`.
- What’s the best way to mock HTTP responses for testing in Laravel?
- Use Symfony’s `MockHttpClient` or `TestHttpClient` to simulate responses. For Laravel’s testing stack, bind a mock client in `phpunit.xml` or `pest.php` and inject it via the service container. Alternatively, create custom stubs with `HttpClientInterface` and return predefined responses.
- Does Symfony HttpClient Contracts support async requests in Laravel?
- Only if you use `symfony/http-client` as the concrete implementation, which supports async via `AsyncHttpClient`. Guzzle’s PSR-18 adapter lacks native async, so you’d need to configure Symfony’s client explicitly. Enable async with `$client->withOptions(['timeout' => null])` or use `AsyncHttpClient` directly.
- Will this work with Laravel 9 or older versions?
- Yes, but with caveats. Laravel 9 requires `symfony/psr-http-message-bridge` to unify PSR-7/18 message types. Older versions may need facade adapters or manual type conversions. Test thoroughly, as dependency injection quirks can arise in pre-8.1 PHP environments.
- How do I handle HTTP errors (non-2xx responses) with Symfony’s contracts?
- By default, Symfony’s `HttpClient` throws exceptions for non-2xx statuses. Disable this with `$client->withOptions(['throw' => false])` or check `$response->getStatusCode()` manually. For Laravel, wrap responses in a service to normalize error handling before returning data.
- What are the performance implications of using Symfony HttpClient Contracts?
- Performance depends on the concrete client. `symfony/http-client` offers connection pooling and HTTP/2 by default, while Guzzle requires manual configuration. Async support adds overhead but improves scalability for I/O-bound tasks. Benchmark with your workload—contracts themselves add negligible overhead.
- Can I use this with Guzzle instead of Symfony’s HttpClient?
- Yes, via the `guzzlehttp/psr7` and `php-http/guzzle7-adapter` packages. Bind `HttpClientInterface` to a Guzzle client wrapped in the adapter. This works well for Laravel projects already using Guzzle, but lose Symfony-specific features like async or middleware stack integration.
- How do I add middleware (e.g., retries, logging) to Symfony’s HttpClient in Laravel?
- Use Symfony’s middleware stack by chaining middleware in the client constructor: `$client->withOptions(['middleware' => [new RetryMiddleware(), new LoggingMiddleware()]]). For Laravel, bind the configured client in `AppServiceProvider` or use decorators to wrap `HttpClientInterface` with custom logic.
- What’s the migration path from Laravel’s Http facade to Symfony contracts?
- Phase 1: Add contracts and a concrete client, then refactor new services to use `HttpClientInterface`. Phase 2: Replace facade calls incrementally, starting with non-critical endpoints. Use Laravel’s `Http` facade as a temporary wrapper if needed, but aim to eliminate it entirely for consistency.