Server-Sent Events is the simplest streaming protocol on the web — one long-lived GET, text frames, done — and most API clients still treat it as an afterthought. In SchemaClient, an SSE stream is a request like any other: connect, watch events land in a live log, and validate each one against a schema as it arrives.
Connect to a stream
Pick SSE from the protocol dropdown in the URL bar and enter the endpoint URL. The Send button becomes Connect (and Disconnect while the stream is open).
Under the hood an SSE stream is a plain GET with Accept: text/event-stream — the
client adds that header automatically. The request panel keeps the familiar
Params | Headers | Auth sub-tabs, and all three apply to that GET, so a bearer
token or a header-placed API key authenticates a stream exactly the way it
authenticates a REST request. One exception: an API key set to query placement is
not appended to stream URLs — add it under Params instead.
Read the event log
Every frame the server sends becomes a row: the event name as a chip, a timestamp,
and the data: payload. Events without an event: field show as message — that
is the spec's default, not a SchemaClient invention. The log autoscrolls while you
are at the bottom, a click on any row opens a pretty-printed detail view, and the
clear button empties the log without disconnecting.
The parser handles the real SSE wire format, not just the happy path: multi-line
data: fields are joined, event: and id: fields are tracked, comment lines
(leading :) are ignored, and both LF and CRLF framing are accepted — which
matters, because hand-rolled SSE servers get framing wrong constantly.
event: created
id: 1042
data: {"id": "9b2f0c1e-...", "total": 18.5}
Reconnects resume where they left off
SchemaClient tracks the last id: it received and sends it as the Last-Event-ID
header on the next connect. Servers that implement resumption replay what you
missed and continue; servers that ignore the header simply start fresh. That part
is the server's decision — the client always offers the id, it cannot force a
replay.
Streams also survive navigation inside the app: the connection is owned by the native side, so switching to another page does not drop it.
Validate events by name
A v2 schema can bind to an SSE feed
with @sse, declaring one schema per event name:
@sse("/events/orders", "event")
schema Event("created") { id: UUID, total: number & min(0) }
@sse("/events/orders", "event")
schema Event("cancelled") { id: UUID, reason: string }
Link the schema to the request and every incoming event is validated live, with a
VALID, INVALID, or no schema badge on its row. The discriminator here is
the frame-level event: field — unlike WebSocket, where the discriminator is a
field inside the JSON payload — so a created event is checked against
Event("created"), a cancelled event against Event("cancelled"), and an event
name you never declared is flagged as unmatched instead of failing.
This is the fastest way to catch drift in an event feed: rename a field on the server and the very next event turns red, with the detail view telling you exactly which field diverged.
Limits worth knowing
- Event bodies over 256 KB are truncated in the log. The stream keeps flowing; only the stored copy of that event is cut.
- The log keeps the most recent 500 events per tab — older rows are dropped. For long soak tests, treat the log as a window, not an archive.
SSE requests save into collections alongside your REST, GraphQL, and WebSocket requests, so a stream you debugged once is a stream your team can reconnect to later.