Skip to main content

HTTP Client Cheat Sheet

Immutability rule: with*() methods return new instances.

Core Entry Points

CanSendHttpRequests

  • send(HttpRequest $request): PendingHttpResponse

HttpClient

  • HttpClient::default(): HttpClient
  • HttpClient::using(string $preset, ?string $basePath = null): HttpClient
  • HttpClient::fromConfig(HttpClientConfig $config): HttpClient
  • HttpClient::fromDriver(CanHandleHttpRequest $driver): HttpClient
  • implements CanSendHttpRequests
  • send(HttpRequest $request): PendingHttpResponse
  • withMiddleware(HttpMiddleware $middleware, ?string $name = null): HttpClient
  • withoutMiddleware(string $name): HttpClient
  • withMiddlewareStack(MiddlewareStack $stack): HttpClient
  • runtime(): HttpClientRuntime
  • config(): HttpClientConfig
  • withSSEStream(): HttpClient is deprecated

HttpClientRuntime

  • HttpClientRuntime::fromConfig(?HttpClientConfig $config, ?CanHandleEvents $events, ?CanHandleHttpRequest $driver, ?CanProvideHttpDrivers $drivers, ?object $clientInstance, ?MiddlewareStack $middlewareStack): HttpClientRuntime (all parameters optional)
  • client(): HttpClient
  • send(HttpRequest $request): PendingHttpResponse
  • withMiddleware(HttpMiddleware $middleware, ?string $name = null): self
  • withoutMiddleware(string $name): self
  • withMiddlewareStack(MiddlewareStack $stack): self
  • driver(): CanHandleHttpRequest
  • middlewareStack(): MiddlewareStack
  • events(): CanHandleEvents
  • config(): HttpClientConfig

HttpClientBuilder

  • new HttpClientBuilder(?CanHandleEvents $events = null)
  • withConfig(HttpClientConfig $config): self
  • withDsn(string $dsn): self
  • withDebugConfig(DebugConfig $debugConfig): self
  • withDriver(CanHandleHttpRequest $driver): self
  • withDrivers(CanProvideHttpDrivers $drivers): self
  • withClientInstance(string $driverName, object $clientInstance): self
  • withMiddleware(HttpMiddleware ...$middleware): self
  • withRetryPolicy(RetryPolicy $policy): self
  • withCircuitBreakerPolicy(CircuitBreakerPolicy $policy, ?CanStoreCircuitBreakerState $stateStore = null): self
  • withIdempotencyMiddleware(IdempotencyMiddleware $middleware): self
  • withMock(?callable $configure = null): self
  • withEventBus(CanHandleEvents $events): self
  • create(): HttpClient
  • createRuntime(): HttpClientRuntime

HttpClientConfigFactory

  • default(): HttpClientConfig

Config

HttpClientConfig

Constructor fields:
  • driver
  • connectTimeout
  • requestTimeout
  • idleTimeout
  • streamChunkSize
  • streamHeaderTimeout
  • failOnError
Methods:
  • HttpClientConfig::group(): string
  • HttpClientConfig::fromPreset(string $preset, ?string $basePath = null): HttpClientConfig
  • HttpClientConfig::fromDsn(string $dsn): HttpClientConfig
  • HttpClientConfig::fromArray(array $config): HttpClientConfig
  • withOverrides(array $overrides): self
  • toArray(): array
Available presets: curl, guzzle, symfony, http-ollama

DebugConfig

Constructor fields:
  • httpEnabled
  • httpTrace
  • httpRequestUrl
  • httpRequestHeaders
  • httpRequestBody
  • httpResponseHeaders
  • httpResponseBody
  • httpResponseStream
  • httpResponseStreamByLine
Methods:
  • DebugConfig::group(): string
  • DebugConfig::fromPreset(string $preset, ?string $basePath = null): DebugConfig
  • DebugConfig::fromArray(array $config): DebugConfig
  • withOverrides(array $overrides): self
  • toArray(): array

Data Types

HttpRequest

Constructor:
  • new HttpRequest(string $url, string $method, array $headers, string|array $body, array $options, ?string $id = null, ?DateTimeImmutable $createdAt = null, ?DateTimeImmutable $updatedAt = null, ?Metadata $metadata = null)
Readonly lifecycle fields:
  • id
  • createdAt
  • updatedAt
  • metadata
Methods:
  • url(): string
  • method(): string
  • headers(?string $key = null): mixed
  • body(): HttpRequestBody
  • options(): array
  • isStreamed(): bool
  • withHeader(string $key, string $value): self
  • withStreaming(bool $streaming): self
  • toArray(): array
  • HttpRequest::fromArray(array $data): HttpRequest

HttpRequestBody

  • new HttpRequestBody(string|array $body)
  • arrays are JSON-encoded
  • strings are sent verbatim
  • JSON encoding failures throw InvalidArgumentException
  • toString(): string
  • toArray(): array

HttpResponse

Factories:
  • HttpResponse::sync(int $statusCode, array $headers, string $body): HttpResponse
  • HttpResponse::streaming(int $statusCode, array $headers, StreamInterface $stream): HttpResponse
  • HttpResponse::empty(): HttpResponse
Methods:
  • statusCode(): int
  • headers(): array
  • body(): string
  • isStreamed(): bool
  • isStreaming(): bool
  • stream(): Generator
  • rawStream(): StreamInterface
  • withStream(StreamInterface $stream): HttpResponse
  • toArray(): array
  • HttpResponse::fromArray(array $data): HttpResponse
Note:
  • body() throws for streamed responses

StreamInterface

  • extends IteratorAggregate<int, string>
  • getIterator(): Traversable
  • isCompleted(): bool

PendingHttpResponse

  • get(): HttpResponse
  • statusCode(): int
  • headers(): array
  • content(): string
  • stream(): Generator
Notes:
  • sync and streamed execution are cached separately
  • get() follows the request streaming flag

Collections

HttpRequestList

  • stores HttpRequest
  • empty(), of(...), fromArray(...), fromSerializedArray(...)
  • all(), first(), last(), isEmpty(), count(), getIterator()
  • withAppended(), withPrepended(), filter()
  • toArray()

HttpResponseList

  • stores Result<HttpResponse, mixed>
  • empty(), of(...), fromArray(...), fromSerializedArray(...)
  • all(), first(), last(), isEmpty(), count(), getIterator()
  • successful(): list<HttpResponse>
  • failed(): list<mixed>
  • hasFailures(), hasSuccesses()
  • successCount(), failureCount()
  • withAppended(Result $response), filter(), map()
  • toArray()
  • pooled request results live in packages/http-pool

Middleware

Contracts and Stack

  • HttpMiddleware::handle(HttpRequest $request, CanHandleHttpRequest $next): HttpResponse
  • MiddlewareStack: append, appendMany, prepend, prependMany, remove, replace, clear, all, has, get, filter, decorate, toDebugArray

Built-in Middleware

  • RetryMiddleware(RetryPolicy $policy)
  • CircuitBreakerMiddleware(CircuitBreakerPolicy $policy, ?CanStoreCircuitBreakerState $store)
  • IdempotencyMiddleware(string $headerName, array $methods, ?array $hostAllowList, ?callable $keyProvider)
  • EventSourceMiddleware(bool $enabled)
    • withListeners(CanListenToHttpEvents ...$listeners): self
    • withParser(callable $parser): self
  • RecordReplayMiddleware(string $mode, ?string $storageDir, bool $fallbackToRealRequests, ?EventDispatcherInterface $events)
    • modes: MODE_PASS, MODE_RECORD, MODE_REPLAY
    • setMode(string $mode): self
    • getMode(): string
    • setStorageDir(string $dir): self
    • setFallbackToRealRequests(bool $fallback): self
    • getRecords(): ?RequestRecords
  • StreamSSEsMiddleware (deprecated, use EventSourceMiddleware::withParser() instead)
Record/replay notes:
  • request identity is method + url + body
  • headers and request options are not part of record/replay matching
  • recording streamed responses buffers the full upstream stream before returning a replayable stream

Drivers

Driver Contract

  • CanHandleHttpRequest::handle(HttpRequest $request): HttpResponse

Driver Registry

  • HttpDriverRegistry::make(): HttpDriverRegistry
  • HttpDriverRegistry::fromArray(array $drivers): HttpDriverRegistry
  • withDriver(string $name, string|callable $driver): self
  • withoutDriver(string $name): self
  • has(string $name): bool
  • driverNames(): array
  • makeDriver(string $name, HttpClientConfig $config, CanHandleEvents $events, ?object $clientInstance = null): CanHandleHttpRequest

Built-in Driver Names

  • curl
  • guzzle
  • symfony

Mock Driver

MockHttpDriver

  • addResponse(HttpResponse|callable $response, string|callable|null $url = null, ?string $method = null, string|callable|null $body = null): self
  • expect(): MockExpectation
  • on(): MockExpectation
  • getReceivedRequests(): array
  • getLastRequest(): ?HttpRequest
  • reset(): self
  • clearResponses(): self

MockExpectation

Matchers:
  • method(), get(), post(), put(), patch(), delete()
  • url(), urlStartsWith(), urlMatches(), path()
  • header(), headers()
  • withStream()
  • bodyEquals(), bodyContains(), bodyMatchesRegex(), withJsonSubset(), body()
  • times()
Replies:
  • reply(HttpResponse|callable $response): MockHttpDriver
  • replyJson(array|string|\JsonSerializable $data, int $status = 200, array $headers = []): MockHttpDriver
  • replyText(string $text, int $status = 200, array $headers = []): MockHttpDriver
  • replyStreamChunks(array $chunks, int $status = 200, array $headers = []): MockHttpDriver
  • replySSEFromJson(array $payloads, bool $addDone = true, int $status = 200, array $headers = []): MockHttpDriver

MockHttpResponseFactory

  • success(int $statusCode = 200, array $headers = [], string $body = '', array $chunks = []): HttpResponse
  • error(int $statusCode = 500, array $headers = [], string $body = '', array $chunks = []): HttpResponse
  • streaming(int $statusCode = 200, array $headers = [], array $chunks = []): HttpResponse
  • json(array|string|\JsonSerializable $data, int $statusCode = 200, array $headers = []): HttpResponse
  • sse(array $payloads, bool $addDone = true, int $statusCode = 200, array $headers = []): HttpResponse
Testing guidance:
  • use withMock(...) for most deterministic client tests
  • use MockHttpDriver directly when you need request inspection or reusable expectations
  • use MockHttpResponseFactory for richer JSON, error, streaming, or SSE reply shapes

Exceptions

  • Base: HttpRequestException
  • Network: NetworkException, ConnectionException, TimeoutException
  • HTTP status: HttpClientErrorException, ServerErrorException
  • Middleware-related: CircuitBreakerOpenException
  • Factory: HttpExceptionFactory::fromStatusCode(int $statusCode, ?HttpRequest $request, ?HttpResponse $response, ?float $duration, ?Throwable $previous): HttpRequestException
Useful exception methods:
  • getRequest(): ?HttpRequest
  • getResponse(): ?HttpResponse
  • getDuration(): ?float
  • getStatusCode(): ?int
  • isRetriable(): bool

Minimal Usage

Basic Request

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();

Streaming Request

$request = (new HttpRequest(
    url: 'https://api.example.com/stream',
    method: 'GET',
    headers: ['Accept' => 'text/event-stream'],
    body: '',
    options: [],
))->withStreaming(true);

foreach ($client->send($request)->stream() as $chunk) {
    echo $chunk;
}

Mock Driver

use Cognesy\Http\Creation\HttpClientBuilder;

$client = (new HttpClientBuilder())
    ->withMock(function ($mock) {
        $mock->expect()
            ->get('https://api.example.com/health')
            ->replyJson(['ok' => true]);
    })
    ->create();

Notes

  • pooling lives in packages/http-pool
  • withDsn() coerces values to HttpClientConfig field types
  • EventSourceMiddleware is the current SSE middleware path