Consuming the stream from a client
A stream is only as good as the client reading it. Browsers ship EventSource for GET-based SSE, but we use POST to send a prompt body, which rules out EventSource. For this workshop we read the stream with curl first, then with a tiny fetch-based JavaScript consumer.
curl -N -X POST http://localhost:8000/deploy-patterns/chat/stream \
-H "Content-Type: application/json" \
-d '{"prompt": "Write a haiku about a slow proxy"}'curl -N disables output buffering so you see each event as it arrives. Without -N the shell would hold the response until the stream ended and the streaming illusion would collapse.
async function streamChat(prompt) {
const res = await fetch("/deploy-patterns/chat/stream", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt }),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { value, done } = await reader.read();
if (done) break;
const text = decoder.decode(value);
for (const line of text.split("\n")) {
if (!line.startsWith("data: ")) continue;
const event = JSON.parse(line.slice(6));
if (event.content) process.stdout.write(event.content);
if (event.done) return;
}
}
}A minimal fetch-based SSE reader. We read the response body as a stream, decode the chunks, split on newline, and parse the data lines. This is the pattern any frontend framework wraps under the hood.
AI prompt: Ask an AI to review your SSE client
Loading practice…
Quiz: Quiz
Loading practice…
Checkpoint: SSE checkpoint
Loading practice…