Skip to content

Streaming

Contents | Previous: Authentication, TLS, and Proxy | Next: Client and Request Lifecycle

After reading this chapter

This chapter processes a response in chunks and sends a request body in parts. Its code comes from each language's HttpClient tutorial.

Streaming moves a large body through a caller callback or provider. Unlike a JSON body, it does not serialize or accumulate the whole body. Response Rules covers status and compression rules.

↗ 크게 보기

The provider and sink are each consumed once while the body moves. This is why the streaming path does not apply replay or transparent decompression.

1. Response Chunks Flow Through a Download Sink

A download sink is a callback invoked for each received body chunk. A raw response carries status, headers, and the body before JSON decoding. The final raw response from a download preserves status and headers; bodies from intermediate redirect responses do not reach the sink.

// download() invokes this sink per received chunk; the current host returns one buffered
// chunk.
std::size_t chunks = 0;
std::size_t bytes = 0;
(void) co_await client.get ("/rooms/" + room_id + "/export")
  .download ([&] (std::string_view chunk) {
      ++chunks;
      bytes += chunk.size ();
  });
std::cout << "download stream: chunks " << chunks << " bytes " << bytes << std::endl;

The example counts each export-body chunk and accumulates the total number of chunks and bytes.

2. Request Chunks Come from a Body Stream Provider

A body stream provider returns the next chunk to send and signals completion with the language's empty value. Its configuration includes the content type.

// body_stream() sends three NDJSON chunks; the host presents its decoded body to the route.
const std::vector<std::string> import_chunks{
  "{\"playerId\":\"p1\",\"text\":\"import-one\"}\n",
  "{\"playerId\":\"p2\",\"text\":\"import-two\"}\n",
  "{\"playerId\":\"p2\",\"text\":\"import-three\"}\n"};
std::size_t next_chunk = 0;
const auto imported = co_await client.post ("/rooms/" + room_id + "/import")
                        .body_stream (
                          [&] () -> std::optional<std::string> {
                              if (next_chunk == import_chunks.size ())
                                  return std::nullopt;
                              return import_chunks[next_chunk++];
                          },
                          "application/x-ndjson")
                        .async<import_response_t> ();
std::cout << "upload stream: imported " << imported.body.imported << std::endl;

The example supplies three NDJSON lines in sequence and confirms that the server imported three items.

3. Retry and Decompression Are Excluded

A download sink and a body stream provider consume their body once and cannot recreate it. A streaming request is therefore excluded from retry and redirect replay. A download sink receives compressed response bytes unchanged; decompression is not applied.

4. Next Chapter

Client and Request Lifecycle covers client reuse, close timing, response completion, and timeout boundaries.