Skip to content

HTTP Client – Opt-in Stream Capture

Overview

Demonstrates opt-in, bounded capture of a streamed response. Capture is disabled by default so long-lived streams do not retain their response bodies in memory.

The example uses a 10-byte preview limit: the complete stream is still emitted, but only its prefix is retained for inspection. For very long streams, prefer preview() with a small limit. chunks() and full() retain one PHP entry per captured chunk; 50,000–100,000 small chunks can therefore consume several times their payload size in array and string overhead, even with a byte cap. The default avoids that retention.

Example

<?php
require 'examples/boot.php';

use Cognesy\Http\Creation\HttpClientBuilder;
use Cognesy\Http\Data\HttpRequest;
use Cognesy\Http\Data\HttpResponse;
use Cognesy\Http\Drivers\Mock\MockHttpDriver;
use Cognesy\Http\Stream\ArrayStream;
use Cognesy\Http\Stream\StreamCapturingPolicy;

// Use a Mock driver so the example is deterministic and does not require a network.
$client = (new HttpClientBuilder())
    ->withMock(function (MockHttpDriver $mock): void {
        $mock->addResponse(
            HttpResponse::streaming(
                statusCode: 200,
                headers: ['Content-Type' => 'text/plain'],
                stream: ArrayStream::from([
                    "alpha\n",
                    "beta\n",
                    "gamma\n",
                ]),
            ),
            url: 'https://api.example.local/stream',
            method: 'GET',
        );
    })
    ->create();

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

// Capture is applied to the concrete response, before its stream is consumed.
$response = $client
    ->send($request)
    ->get()
    ->withStreamCapture(
        StreamCapturingPolicy::preview(maxBytes: 10),
    );

foreach ($response->stream() as $chunk) {
    echo $chunk;
}

$capture = $response->streamCapture();
assert($capture !== null, 'Expected stream capture to be enabled');

$stats = $capture->stats();

echo 'Capture: ' . json_encode([
    'preview' => $capture->preview(),
    'bytes' => $stats->bytes,
    'chunks' => $stats->chunks,
    'capturedBytes' => $stats->capturedBytes,
    'truncated' => $stats->truncated,
], JSON_UNESCAPED_SLASHES) . PHP_EOL;

assert($stats->bytes === 17, 'Expected all stream bytes to be counted');
assert($stats->chunks === 3, 'Expected all stream chunks to be counted');
assert($stats->capturedBytes === 10, 'Expected the capture to be bounded');
assert($capture->preview() === "alpha\nbeta", 'Expected a bounded preview');
assert($stats->truncated, 'Expected the preview to report truncation');
?>