Installation Update Composer to require the latest version (PHP 8.1+):
composer require php-http/curl-client:^2.4.0
Require the Http\Adapter\Curl\Client in your Laravel project (PHP 8.1+):
use Http\Adapter\Curl\Client;
use Http\Message\MessageFactory\GuzzleMessageFactory;
Basic HTTP Request Initialize the client with a message factory (e.g., Guzzle's):
$messageFactory = new GuzzleMessageFactory();
$client = new Client($messageFactory);
Send a simple GET request (PHP 8.1+):
$response = $client->get('https://api.example.com/users');
$body = (string) $response->getBody();
First Use Case: API Integration
Use the client to interact with external APIs in Laravel's Http facade or service containers:
$response = $client->sendRequest(new \Http\Message\Request('GET', 'https://api.example.com/data'));
Request Construction Build requests with headers, body, and authentication (PHP 8.1+):
$request = new \Http\Message\Request('POST', 'https://api.example.com/users');
$request = $request->withBody(\GuzzleHttp\Psr7\stream_for(json_encode(['name' => 'John'])));
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withHeader('Authorization', 'Bearer ' . $token);
Middleware/Plugins Leverage built-in plugins for common tasks (PHP 8.1+):
$plugins = [
new \Http\Client\Common\Plugin\HeaderSetPlugin(['User-Agent' => 'Laravel/1.0']),
new \Http\Client\Common\Plugin\BaseUrlPlugin('https://api.example.com/v1'),
];
$client = new Client($messageFactory, ['plugins' => $plugins]);
Retry Logic
Use RetryPlugin for transient failures (PHP 8.1+):
use Http\Client\Common\Plugin\RetryPlugin;
$retryPlugin = new RetryPlugin(function ($response) {
return 500 <= $response->getStatusCode() && $response->getStatusCode() < 600;
});
$client->addPlugin($retryPlugin);
Laravel Service Provider Bind the client to Laravel's container for dependency injection (PHP 8.1+):
public function register()
{
$this->app->singleton(\Http\Client\ClientInterface::class, function ($app) {
$messageFactory = new GuzzleMessageFactory();
$client = new Client($messageFactory);
return $client;
});
}
Async Requests (with ReactPHP) Integrate with ReactPHP for non-blocking calls (PHP 8.1+):
$loop = React\EventLoop\Factory::create();
$connector = new \Http\Adapter\React\Client($loop);
$client = new \Http\Client\Common\Plugin\Client($connector);
Symfony 8 Integration New Feature: Leverage Symfony 8 components for advanced HTTP handling (PHP 8.1+):
// Example: Using Symfony's HttpClient for integration with Symfony 8
$symfonyClient = new \Symfony\Contracts\HttpClient\HttpClient();
$symfonyResponse = $symfonyClient->request('GET', 'https://api.example.com/data');
$body = $symfonyResponse->getContent();
PHP Version Compatibility Breaking Change: PHP < 8.1 is no longer supported. Update your environment:
# Ensure PHP 8.1+ is used
php -v
New Feature: PHP 8.5 is now supported, enabling use of newer language features like typed properties and enums.
SSL Verification Disable SSL verification only in development (never in production):
$client = new Client($messageFactory, [
'curl.options' => [
CURLOPT_SSL_VERIFYPEER => false,
],
]);
Header Conflicts
Plugins like HeaderSetPlugin and HeaderAppendPlugin can override each other. Order matters (PHP 8.1+):
// HeaderSetPlugin will overwrite HeaderAppendPlugin's values
$plugins = [
new \Http\Client\Common\Plugin\HeaderAppendPlugin(['X-Custom' => 'value']),
new \Http\Client\Common\Plugin\HeaderSetPlugin(['X-Custom' => 'new-value']),
];
Immutable Requests
The Http\Message\Request object is immutable. Use with* methods for modifications (PHP 8.1+):
$newRequest = $request->withHeader('X-New', 'value');
Resource Leaks
Always ensure responses are consumed (e.g., (string) $response->getBody()) to avoid memory leaks.
Enable cURL Debugging Capture cURL debug output for troubleshooting (PHP 8.1+):
$client = new Client($messageFactory, [
'curl.options' => [
CURLOPT_VERBOSE => true,
CURLOPT_STDERR => fopen('php://temp', 'w+'),
],
]);
Logging Responses Use a plugin to log responses (PHP 8.1+):
$client->addPlugin(new class {
public function __invoke(callable $next, \Http\Message\RequestInterface $request) {
$response = $next($request);
\Log::debug('Response:', [
'status' => $response->getStatusCode(),
'body' => (string) $response->getBody(),
]);
return $response;
}
});
Custom Plugins Create reusable plugins for cross-cutting concerns (e.g., rate limiting) (PHP 8.1+):
$client->addPlugin(new class {
public function __invoke(callable $next, \Http\Message\RequestInterface $request) {
if ($this->shouldRateLimit()) {
sleep(1);
}
return $next($request);
}
});
Adapter Swapping
Replace Curl\Client with Guzzle\Client or Symfony\Panther\Client for testing (PHP 8.1+):
$adapter = new \Http\Adapter\Guzzle6\Client();
$client = new \Http\Client\Common\Plugin\Client($adapter);
Middleware Integration Use Laravel's middleware to transform requests/responses (PHP 8.1+):
$client->addPlugin(new class {
public function __invoke(callable $next, \Http\Message\RequestInterface $request) {
$request = $request->withHeader('X-Laravel', 'true');
$response = $next($request);
return $response->withAddedHeader('X-Processed', 'true');
}
});
Mocking for Tests
Use Http\Mock\Client for unit testing (PHP 8.1+):
$mock = new \Http\Mock\Client();
$mock->addResponse(new \Http\Message\Response(200, [], 'Mocked response'));
Symfony 8 Integration New Feature: Utilize Symfony 8's HttpClient for advanced use cases (PHP 8.1+):
// Example: Using Symfony's HttpClient for integration with Symfony 8
$symfonyClient = \Symfony\Component\HttpClient\HttpClient::create();
$response = $symfonyClient->request('GET', 'https://api.example.com/data');
$content = $response->getContent();
PHP 8.5 Features New Feature: Leverage PHP 8.5 features like typed class constants and first-class callable expressions:
// Example: Using typed class constants
const string BASE_URL = 'https://api.example.com';
// Example: Using first-class callable expressions
$client->addPlugin(fn(callable $next, \Http\Message\RequestInterface $request) => {
return $next($request->withHeader('X-New-Feature', 'PHP8.5'));
});
How can I help you explore Laravel packages today?