Stream
You can return a continuous application stream with ResponseContract.stream for binary chunks, or ResponseContract.streamText for text chunks.
ts
import { ResponseContract, useRouteBuilder } from "@duplojs/http";
import { DPE, sleep } from "@duplojs/utils";
useRouteBuilder("GET", "/binary-stream")
.handler(
ResponseContract.stream(
"binary-stream",
DPE.number(),
),
(__, { streamResponse }) => streamResponse(
"binary-stream",
async({ send }) => {
await send(12);
await sleep(500);
await send(20);
},
),
);
useRouteBuilder("POST", "/text-stream")
.extract({
body: {
value: DPE.string(),
},
})
.handler(
ResponseContract.streamText("text-stream"),
({ value }, { streamTextResponse }) => streamTextResponse(
"text-stream",
async({ send }) => {
await send("hello");
await sleep(500);
await send(` ${value}`);
},
),
);stream is suited for opaque chunks on the client side. streamText is more convenient when you want to consume strings directly.
Consume the stream on the client
The client detects this response type automatically and returns an iterable object enriched with onStream hooks.
ts
import { createHttpClient } from "@duplojs/http/client";
import { type Routes } from "./types";
const client = createHttpClient<Routes>({
baseUrl: "http://localhost:1506",
});
const binaryResponse = await client
.get("/binary-stream")
.iWantInformationOrThrow("binary-stream");
binaryResponse.onStream("receiveData", (chunk) => {
});
for await (const chunk of binaryResponse) {
// ...
}
const textResponse = await client
.post(
"/text-stream",
{ body: { value: "world" } },
)
.iWantInformationOrThrow("text-stream");
textResponse.onStream("receiveData", (chunk) => {
});
void textResponse.consumeStream();To consume the stream, either iterate over the response with for await...of, or call consumeStream(). The receiveData event receives the chunk type that matches the generated client contract.
