docs Protocols
WebSocket and SSE
Server-Sent Events and WebSocket sessions, transcripts and the live console.
Streaming sessions show up in the Stream response tab and are saved in history. Captures and scripts can read them too. A request uses SSE or WebSocket, not both. GraphQL can run over either one, as GraphQL subscriptions describes, and a GRPC request can use none of them.
Server-Sent Events (@sse)
Add # @sse to keep an HTTP request open for events:
### Notifications
# @name notifications
# @sse duration=2m idle=15s max-events=250
GET https://api.example.com/notifications@sse off turns SSE off again and clears the options set so far. Other false values such as false or disable work too.
@sse accepts the following options:
| Token | Description |
|---|---|
duration / timeout |
Maximum lifetime of the stream. Resterm cancels the request once the timer elapses. |
idle / idle-timeout |
Longest time to wait for more data. Resterm cancels the request if no data arrives before this time. This limit is separate from duration. |
max-events |
Stop after this many events. |
max-bytes / limit-bytes |
Maximum amount of stream data to read, after gzip decoding. The stream ends when it reaches this limit. |
max-line-bytes |
Largest allowed line. The default is 4 MiB, or whatever @setting sse-max-line-bytes sets. A larger line stops the stream with an error. |
max-event-bytes |
Largest allowed event, counting every line it is built from. The default is 8 MiB, or whatever @setting sse-max-event-bytes sets. A larger event stops the stream with an error. |
Resterm decodes a gzip stream as it reads it, also when the request sets its own Accept-Encoding, so events, byteCount, and every limit use the decoded data. If the server returns a non-2xx status or a content type other than text/event-stream, Resterm shows a normal HTTP response so you can inspect it. For a successful stream, Resterm shows the events and their details in the Stream tab and saves them in history. Templates and scripts can read eventCount, byteCount, duration, reason, error, errorClass, and dropped from the summary. A non-zero dropped value means the retained transcript is incomplete. reason has one of these values:
| Reason | Meaning |
|---|---|
eof |
The server closed the stream. |
complete |
A GraphQL operation sent its complete event. |
timeout:idle |
The stream went quiet for longer than idle. |
timeout:total |
The stream ran for longer than duration. |
limit:max_events |
max-events was reached. |
limit:max_bytes |
max-bytes was reached. |
limit:line_bytes |
One line was larger than max-line-bytes. |
limit:event_bytes |
One event was larger than max-event-bytes. |
context_canceled |
The run was canceled. |
context_deadline |
The run's deadline expired before the stream reached one of its own limits. |
error |
The stream failed. summary.error contains the error message and summary.errorClass names what kind of failure it was. |
A configured duration is a normal limit. An expired run deadline is a timeout failure. Limits lists which endings fail the request.
Resterm reads events the way the SSE specification describes. Lines can end with CRLF, LF, or CR. A byte order mark before the first line is dropped, and one space after a field's colon is removed. A retry value that is not only digits, or is over 2147483647, is ignored and does not fail the stream. The transcript is for inspecting what the server sent, so it also keeps what a browser EventSource drops: comments, blocks without a data line, and an unfinished block when the server closes the stream. Each event's id is the one sent in its own block, not the last id seen.
WebSockets (@websocket, @ws)
Use # @websocket to upgrade the connection, then script the session with # @ws lines:
### Chat session
# @name chatSession
# @websocket timeout=10s idle-timeout=4s subprotocols=chat.v2,json compression=true
# @ws send {"type":"hello"}
# @ws wait 1s
# @ws send-json {"type":"message","text":"Hello from Resterm"}
# @ws ping heartbeat
# @ws close 1000 "client done"
GET wss://chat.example.com/roomA @ws step also turns WebSocket on. @websocket off turns WebSocket off again and clears the options and steps set so far. Other false values such as false or disable work too.
Available WebSocket options:
| Token | Description |
|---|---|
timeout |
Handshake deadline (applies until the connection upgrades). |
idle-timeout / idle |
Idle timeout once the socket is open. Resets on every frame Resterm sends and every message it receives. Pings and pongs from the server do not reset it. Set it to 0 for no limit. |
max-message-bytes |
Largest inbound message allowed. The default is 32 KiB. |
subprotocols / subprotocol |
Comma-separated list advertised during the handshake. A @graphql request offers graphql-transport-ws, and any other value is a parse error. |
compression=<true|false> |
Offer per-message compression to the server. The default is true, and false turns it off. To change the default for a whole file or an environment, use the ws-compression setting, for example # @setting ws-compression false. |
Supported @ws steps:
| Step | Effect |
|---|---|
@ws send <text> |
Send a UTF-8 text frame. Templates expand before sending. |
@ws send-json <object> |
Encode JSON and send it as text. |
@ws send-base64 <data> |
Decode base64 and send the result as binary. |
@ws send-file <path> |
Send a file from disk (relative to the request file unless absolute). |
@ws ping [payload] / @ws pong [payload] |
Send control frames (payload up to 125 bytes). |
@ws wait <duration> |
Pause for the given duration, for example 500ms. |
@ws close [code] [reason] |
Close the connection with an optional status code (defaults to 1000). Quotes around the reason are optional. |
When the server refuses the upgrade, Resterm shows its HTTP response to help you find the problem. An upgrade with an invalid handshake, such as a subprotocol Resterm did not offer, fails the request. During a successful session, events appear in the UI and history together with their direction, opcode, size, and close status. Pings and pongs from the server are listed as received frames and count toward receivedCount, as sent pings count toward sentCount. Resterm answers each ping. Templates and scripts can read sentCount, receivedCount, duration, closedBy, closeCode, closeReason, errorClass, and dropped from the summary. closedBy has one of these values:
| Value | Meaning |
|---|---|
server |
The server closed the connection. |
client |
Resterm closed the connection through @ws close, after the last step, or after a GraphQL operation ended. Resterm records what the server sends until it answers, for up to 5 seconds after the close is sent. A server that does not answer does not fail the request. |
timeout |
The idle limit was reached, or the run's deadline expired. An idle timeout is a normal ending. An expired run deadline is a failure and sets errorClass to timeout. |
canceled |
The run was canceled. |
error |
The session failed. closeReason contains the error message and errorClass names what kind of failure it was. |
error, canceled, and a timeout with an errorClass cause the request to fail. Resterm keeps the transcript in every case.
Heads-up: When you keep a WebSocket URL in
@const,@global, or@var, write the request line asGET {{ws.url}}(or whichever variable you use). The parser needs the explicit method to recognize the line as a WebSocket request before template expansion. Literalws:///wss://URLs without a method still work when written directly.
Limits
-
SSE lines are limited to 4 MiB and SSE events to 8 MiB. Change these limits with
@sse max-line-bytesand@sse max-event-bytes. A larger line or event stops the stream with an error naming the limit to raise. Reaching@sse max-bytesends the stream without an error. WebSocket messages are limited to 32 KiB unless@websocket max-message-bytessets another limit. A larger message stops the session with an error naming that option. -
To change these limits for more than one request, use the
sse-max-line-bytes,sse-max-event-bytes, andws-max-message-bytessettings. They take a size such as8mband set the default every request starts from, so an environment or a file can raise a limit once instead of repeating it. A@sseor@websocketdirective on the request still wins. These settings do not acceptnone, because a stream with no line limit has nothing to stop it.http # @setting sse-max-line-bytes 16mb # @setting ws-max-message-bytes 1mb -
Most events arrive as a single
data:line, so the line limit is the one they reach first. Raisemax-line-bytesalong withmax-event-byteswhen a single line carries the whole payload. Base64 adds about a third to a payload, so a 3 MiB file needs roughly 4 MiB of headroom. -
Resterm limits how much stream data it keeps in memory. An SSE session keeps up to 1024 events and 16 MiB, or twice
max-event-byteswhen that is larger. The size of an SSE event includes its data, comment, id, name, and other saved fields. A WebSocket session and its saved transcript each have an 8 MiB limit. The Stream pane keeps up to 5000 events or 16 MiB. If Resterm removes older events, the summary counts them indropped. The Stream tab showsTranscript incompletewhen its view is missing events. -
Reaching
max-events,max-bytes,idle, ordurationis a normal way for a stream to end, except thatidlefails a GraphQL WebSocket that has not receivedconnection_ack. The saved data includes everything read before the limit was reached. Other problems fail the request. These include an expired run deadline, a read error such as gzip data that cannot be decoded, an event stream in a content encoding Resterm cannot decode, an SSE line or event that exceeds its limit, a GraphQL message that breaks its protocol, and a WebSocket session that ends withclosedBy: error. Resterm still saves and reports the transcript it collected. With detailed exit codes, a canceled run returns130. A stream error returns the code for the failure named insummary.errorClass:20fortimeout,21fornetwork,22fortls,25forfilesystemsuch as an@ws send-filepayload Resterm could not read, and26forprotocol. A stream that failed for a reason Resterm cannot name reportsprotocol.
Stream tab, history, and console
- The Stream tab appears automatically whenever a streaming session is active. Scroll to review frames, press
Ctrl+Bto bookmark important events, and switch tabs with the arrow keys (Ctrl+H/Ctrl+L). - While the Stream tab is focused, use
g+wthenito toggle the interactive WebSocket console,pto send ping,cto close gracefully, orlto clear the live buffer. If the console is focused for typing, pressEscfirst. Inside the console, cycle payload modes withF2, send payloads withCtrl+SorCtrl+Enter, and reuse previous payloads with the arrow keys. - Finished transcripts are saved with the request in history, along with summary headers (
X-Resterm-Stream-Type,X-Resterm-Stream-Summary). Scripts and captures can read the same data throughstream.*templates and APIs. See Scripting.