I wanted to understand AI streaming by building it—not just reading about it.
So I added a streaming command to my OpenAI SDK practice project using JavaScript and the OpenAI Responses API.
The goal was simple: instead of waiting for the entire AI response, display text fragments as they arrive.
Along the way, I got to practise something I care about just as much as the implementation: making an example understandable, testable, and useful to the next developer.
Here is what I built and what I learned.
Project: OpenAI SDK Docs Practice on GitHub
1. The streaming function
The core implementation is a small asynchronous function:
export async function streamText(client, prompt, onText) {
if (typeof prompt !== "string" || !prompt.trim()) {
throw new Error("Prompt is required.");
}
if (typeof onText !== "function") {
throw new Error("A text callback is required.");
}
const stream = await client.responses.create({
model: MODEL,
input: prompt,
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
onText(event.delta);
}
}
}
MODEL is defined elsewhere in the project.
A few things are happening here:
- I validate the prompt before making the request.
- I validate the callback so the caller has a way to receive text.
- I enable streaming in the API request.
- I consume the asynchronous event stream.
- I forward only text-delta events to the callback.
In the command-line interface, the callback uses process.stdout.write() to display each fragment as it arrives.
To run the example with a valid API key configured locally:
node index.js stream "Explain how an API works"
The project uses OPENAI_API_KEY from a local .env file. Never commit a real API key to your repository.
2. What I decided to test
I didn't want to stop at checking that the function returned without throwing.
Because streaming is event-driven, I wanted to check what happened as different events arrived.
I created a mocked client that yields simulated events, including two text fragments and a completion event.
The test verifies that the received fragments are:
["Hello", ", developer!"]
Joining them produces:
Hello, developer!
The completion event isn't forwarded to the text callback.
I also added coverage for:
- Ignoring non-text events
- Rejecting an empty prompt
- Rejecting a missing callback
- Propagating an SDK error when stream startup fails
This makes the tests repeatable without depending on a network connection or consuming API usage.
3. The result—and an important limitation
The latest reported run of the project's automated test suite was:
19 passed, 0 failed.
That is a useful milestone, but I want to be precise about what it means.
The streaming tests use mocked events. I haven't tested a live API stream because I don't currently have an API key.
The tests verify my application's behavior with the events and failures I simulate. They don't prove that a real provider request succeeds or that the implementation handles every possible interruption.
My next improvements would include testing a stream interrupted after some text has already arrived, defining how partial output should be reported, and verifying a live integration when credentials are available.
4. The documentation is part of the feature
I also documented the implementation in STREAMING-COOKBOOK.md.
It covers:
- Prerequisites
- How the streaming function works
- The command to run
- How to execute the automated tests
- Common setup and troubleshooting issues
- What has and hasn't been verified
This exercise reminded me that a code example is much more useful when someone else can follow it without guessing.
A working snippet alone doesn't explain how to configure it, test it, or diagnose a failure.
5. What I learned about Developer Experience
The biggest lesson wasn't simply how to use stream: true.
It was how much of the developer experience lives around the API call:
Validate → Request → Consume events → Handle errors → Test → Document
Every step gives the next developer more confidence and fewer surprises.
I'm building these examples as part of my journey into AI Developer Documentation and Developer Experience. I want to be able to build the integration, understand its limitations, and explain it clearly—not just write a tutorial around code I haven't tested.
If you'd like to explore the project, here's the repository:
I'd love to learn from other developers
When you're implementing a streaming API, which edge case do you make sure to test first?
- A failure before the stream starts
- A connection dropping halfway through
- Cancellation when the user leaves the page
- Handling partial output after a failure
I'd be interested to hear how you approach it.
Verification note: Automated tests passed in the latest reported run, using mocked streaming events. Live API streaming has not yet been verified.
Top comments (0)