Installation:
composer require e-moe/guzzle6-bundle
Enable the bundle in config/bundles.php:
EMoE\Guzzle6Bundle\EMoEGuzzle6Bundle::class => ['all' => true],
First Use Case:
Inject the GuzzleClient service into a controller or service:
use GuzzleHttp\Client;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class MyController extends Controller
{
public function __construct(private Client $client)
{
}
public function fetchData()
{
$response = $this->client->get('https://api.example.com/data');
return new Response($response->getBody());
}
}
Configuration:
Configure default options in config/packages/emoe_guzzle6.yaml:
emo_guzzle6:
clients:
default:
base_uri: 'https://api.example.com'
timeout: 10
headers:
Accept: 'application/json'
Service Integration:
Use the Client service directly in controllers, services, or command classes. The bundle provides a single default client by default, but you can define multiple clients in configuration.
Custom Clients:
Define named clients in config/packages/emoe_guzzle6.yaml:
emo_guzzle6:
clients:
api:
base_uri: 'https://api.example.com/v1'
timeout: 5
external:
base_uri: 'https://external-service.com'
headers:
Authorization: 'Bearer %token%'
Inject them via autowiring or constructor:
public function __construct(private Client $apiClient, private Client $externalClient)
{
}
Middleware: Attach middleware to specific clients or globally:
emo_guzzle6:
clients:
default:
middleware:
- EMoE\Guzzle6Bundle\Middleware\MyCustomMiddleware
Create middleware by implementing GuzzleHttp\Promise\PromiseInterface or using GuzzleHttp\Middleware.
Handlers:
Use Symfony’s HTTP client handlers (e.g., Symfony\Component\HttpClient\EventListener\EventListenerInterface) if integrating with Symfony’s HTTP client stack.
Promises: Leverage Guzzle’s promise-based API for async requests:
$promise = $this->client->getAsync('https://api.example.com/data');
$response = $promise->wait();
Event Dispatching: Dispatch events for async responses using Symfony’s event system:
$promise = $this->client->getAsync('https://api.example.com/data')
->then(function (ResponseInterface $response) {
// Handle response
})
->otherwise(function (Exception $e) {
// Handle error
});
Mocking:
Use PHPUnit’s mocking tools to replace Client in tests:
$mockClient = $this->createMock(Client::class);
$mockClient->method('get')->willReturn(new Response(200, [], '{}'));
$controller = new MyController($mockClient);
HttpClient Integration:
For Symfony 5+, prefer Symfony\Contracts\HttpClient\HttpClientInterface for testing, but wrap Guzzle clients if needed:
$httpClient = new HttpClient([
new GuzzleAdapter($this->client),
]);
YAML Syntax: Ensure YAML configuration is correctly indented. Misalignment can lead to silent failures or unexpected behavior.
# Correct:
emo_guzzle6:
clients:
api:
base_uri: 'https://api.example.com'
timeout: 10
# Incorrect (will fail silently):
emo_guzzle6:
clients:
api:
base_uri: 'https://api.example.com' # Missing indentation
Environment Variables:
Use %env% for dynamic values (e.g., tokens, URLs):
emo_guzzle6:
clients:
api:
base_uri: '%env(API_URL)%'
headers:
Authorization: 'Bearer %env(API_TOKEN)%'
Logging: Enable Guzzle’s debug middleware for logging requests/responses:
emo_guzzle6:
clients:
default:
middleware:
- GuzzleHttp\Middleware::tap(
function ($request, $options) {
$this->logger->debug('Request:', [
'url' => (string) $request->getUri(),
'method' => $request->getMethod(),
]);
}
)
Exceptions:
Catch GuzzleHttp\Exception\RequestException for HTTP errors and GuzzleHttp\Exception\ConnectException for connection issues:
try {
$response = $this->client->get('https://api.example.com/data');
} catch (RequestException $e) {
$response = $e->getResponse();
// Handle error (e.g., 404, 500)
}
Custom Clients:
Extend the bundle’s ClientFactory to add logic for client creation:
use EMoE\Guzzle6Bundle\Client\ClientFactory;
use GuzzleHttp\Client;
class CustomClientFactory extends ClientFactory
{
public function createClient(array $config): Client
{
$client = parent::createClient($config);
// Add custom logic (e.g., interceptors)
return $client;
}
}
Register the service in services.yaml:
services:
EMoE\Guzzle6Bundle\Client\ClientFactory:
class: App\CustomClientFactory
Event Subscribers:
Subscribe to Guzzle events (e.g., request, response) using Symfony’s event system:
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use GuzzleHttp\Event\RequestEvents;
class GuzzleSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
RequestEvents::PRE_REQUEST => 'onPreRequest',
];
}
public function onPreRequest()
{
// Modify request before sending
}
}
Guzzle 6 vs. 7:
This bundle is for Guzzle 6.x. If migrating to Guzzle 7+, consider alternatives like symfony/http-client or guzzlehttp/guzzle with custom integration.
composer.json to use guzzlehttp/guzzle:^7.0 and refactor middleware/event handling.Symfony 5+:
Symfony 5+ encourages Symfony\Contracts\HttpClient\HttpClientInterface. For new projects, evaluate whether to:
symfony/http-client with a Guzzle adapter.Connection Pooling:
Reuse clients (e.g., inject a single Client instance) to leverage HTTP connection pooling:
// Good: Reuse client
$this->client->get('...');
// Bad: Create new clients per request (inefficient)
$client = new Client(['base_uri' => '...']);
$client->get('...');
Async Batching:
Use GuzzleHttp\Pool for batching async requests:
$pool = new Pool($this->client, $requests, [
'concurrency' => 10,
'fulfilled' => function (Response $response, $index) {
// Handle response
},
'rejected' => function ($reason, $index) {
// Handle error
},
]);
$pool->promise()->wait();
How can I help you explore Laravel packages today?