Skip to content

Getting Started

Installation

Install the package via Composer:

composer require cognesy/instructor-http-client

You also need at least one supported HTTP library. The default driver uses PHP's built-in cURL extension, so if cURL is available you can start immediately. For other drivers, install the corresponding package:

# Guzzle
composer require guzzlehttp/guzzle

# Symfony HttpClient
composer require symfony/http-client

Requirements

  • PHP 8.2 or higher
  • JSON extension
  • cURL extension (included by default in most PHP installations)

Sending Your First Request

Using the HTTP client involves three steps: create a client, build a request, and read the response.

use Cognesy\Http\Data\HttpRequest;
use Cognesy\Http\HttpClient;

$client = HttpClient::default();

$response = $client->send(new HttpRequest(
    url: 'https://api.example.com/health',
    method: 'GET',
    headers: ['Accept' => 'application/json'],
    body: '',
    options: [],
))->get();

echo $response->statusCode(); // 200
echo $response->body();       // {"status":"ok"}

HttpClient::default() creates a client with the default cURL driver. The send() method returns a PendingHttpResponse, which is lazy -- the network call does not happen until you call get() or stream().

Choosing a Driver

If you want a specific driver, use a preset name or pass an HttpClientConfig:

use Cognesy\Http\HttpClient;

$client = HttpClient::using('guzzle');

Or construct the config explicitly:

use Cognesy\Http\Config\HttpClientConfig;
use Cognesy\Http\HttpClient;

$client = HttpClient::fromConfig(new HttpClientConfig(driver: 'guzzle'));

Or use the builder for more control:

use Cognesy\Http\Config\HttpClientConfig;
use Cognesy\Http\Creation\HttpClientBuilder;

$client = (new HttpClientBuilder())
    ->withConfig(new HttpClientConfig(
        driver: 'symfony',
        connectTimeout: 5,
        requestTimeout: 30,
    ))
    ->create();

Error Handling

HTTP requests can fail for many reasons. Wrap your calls in a try-catch block:

use Cognesy\Http\Exceptions\HttpRequestException;

try {
    $response = $client->send($request)->get();
} catch (HttpRequestException $e) {
    echo "Request failed: {$e->getMessage()}\n";

    if ($e->getResponse()) {
        echo "Status: {$e->getResponse()->statusCode()}\n";
    }
}

The exception hierarchy gives you granular control:

Exception When
HttpRequestException Base class for all HTTP errors
NetworkException Network-level failures
ConnectionException Could not connect to the host
TimeoutException Connect or request timeout exceeded
HttpClientErrorException HTTP 4xx response (when failOnError is true)
ServerErrorException HTTP 5xx response (when failOnError is true)
CircuitBreakerOpenException Circuit breaker is open for the target host

When failOnError is set to true in the config, the client throws typed exceptions for 4xx and 5xx responses automatically. When it is false (the default), you need to check the status code yourself.

Testing with Mocks

For tests, use the builder's withMock() method to supply predefined responses without making real HTTP calls:

use Cognesy\Http\Creation\HttpClientBuilder;
use Cognesy\Http\Data\HttpResponse;

$client = (new HttpClientBuilder())
    ->withMock(function ($mock) {
        $mock->addResponse(
            HttpResponse::sync(200, ['Content-Type' => 'application/json'], '{"ok":true}'),
            url: 'https://api.example.com/health',
            method: 'GET',
        );
    })
    ->create();

$response = $client->send(new HttpRequest(
    url: 'https://api.example.com/health',
    method: 'GET',
    headers: [],
    body: '',
    options: [],
))->get();

echo $response->body(); // {"ok":true}

The mock driver matches responses by URL and method, making it straightforward to verify that your application sends the right requests.

What's Next

Now that you have a working client, explore the rest of the documentation: