Server-Sent Events
Instead of returning one response, you can stream events with an async generator. Every yielded object is sent to the client as an event.
The supported methods are: getSSE, postSSE, putSSE, patchSSE, deleteSSE
Example
builder
.chain(authLink)
.getSSE(async function* ({ data, disconnectSignal }) {
for await (const event of activityFeed.subscribe(disconnectSignal)) {
yield { action: event.action, by: data.account.name };
}
});
In this example:
- Middlewares run before the stream opens. Opening a stream sends the status (
200) first, so after that an error can only close the stream. Running auth and validation before it means a rejection is still a normal JSON result with its own status. - When the client disconnects, the generator is stopped, and
disconnectSignalis aborted.
Client
const stream = await fetchCupleSSE(client.activity.get, {}).thenKeepSuccess();
for await (const event of stream) {
console.log(event.by, event.action);
}
Like fetchCuple, it resolves with any result the server sent: a rejection by a middleware is a JSON result, not a stream. thenKeepSuccess() keeps only the stream.
In React, use useStream.
- NOTE: By default the generator is stopped when the client disconnects, so a client that navigates away doesn't leave a subscription or a loop running on the server. If your generator ends on its own, and it should finish even without the client, use
getSSE(generator, { returnOnDisconnect: false }). Never do this with an endless loop.
A stream is an async generator because yield is the closest thing to return: a handler that streams reads like one that responds once, and the yielded type flows to the client.
SSE is here because it was low-hanging fruit on plain HTTP. WebSockets are planned. The separate methods (getSSE, postSSE, …) are a typing limit and an ergonomics choice: a streaming handler has a different type from a normal one.