Most WebSocket testing is squinting at a stream of frames and hoping you would notice a wrong one. SchemaClient treats a WebSocket session like any other request — same URL bar, same auth, same collections — and, if you link a schema, validates every frame in both directions while you watch.
Switch the request to WS
In the URL bar, flip the protocol dropdown from REST to WS and enter a
ws:// or wss:// URL. The Send button becomes Connect — and
Disconnect once you are connected.
Two things worth knowing about the connection itself:
- Headers and auth ride on the handshake. A WebSocket starts life as an HTTP upgrade request, and that is where SchemaClient sends your headers and auth (bearer, basic, or a header-placed API key). Set them in the Headers and Auth sub-tabs before connecting. Query params you add to the URL apply the same way — and that is also the route for an API key that belongs in the query string, since the query placement option is not applied on streaming connections.
- The connection lives in the native layer, not the page. You can navigate to Monitor or Collections and come back — the socket stays open and keeps receiving while you are away.
Send and read messages
The request panel has three sub-tabs: Message, Headers, and Auth. The Message tab is a JSON editor with a Send message button, which stays disabled until you connect.
The response side is a live log. Each row shows a direction arrow (sent or received) and a timestamp; click a row for a pretty-printed detail view. The log autoscrolls while you are at the bottom, pauses when you scroll up to read, and resumes when you return to the bottom. A trash button clears the log, and a counter shows how many messages it currently holds (the log keeps the most recent 500).
Binary frames appear as [binary frame, N bytes] — you can see that they
arrived and how big they are, but they are not editable or validatable.
Validate every frame with a schema
This is the part a browser console cannot do. Link a schema via the schema selector chip in the panel, and declare your message shapes:
@websocket("/ws/chat", "type")
schema Send("message") { text: string }
@websocket("/ws/chat", "type")
schema Receive("message") { from: string, text: string }
The second argument to @websocket names the discriminator field: for each
JSON frame, SchemaClient reads that field (here type) and its value picks which
Send or Receive schema applies. Every frame in both directions is checked
live — each log row gets a VALID, INVALID, or no schema badge, and
invalid rows show field-level errors in the detail view.
Non-JSON text frames show as no schema, never as errors. An unmatched frame is a frame you have not described yet, not a failure.
Try it
Point a WS request at any echo server — a local one, or a public one such as
wss://echo.websocket.org. An echo server sends back exactly what you sent, so
declare the received shape to match the sent one. The path in @websocket(...)
must match the path of the URL you connect to — for wss://echo.websocket.org
that is /:
@websocket("/", "type")
schema Send("message") { text: string }
@websocket("/", "type")
schema Receive("message") { text: string }
Connect, then send:
{ "type": "message", "text": "hello" }
Both rows badge VALID. (The public echo server also greets you with a
plain-text line on connect — that row shows as no schema, which is the
unmatched-frame behavior described above, not a failure.) Now send
{ "type": "message", "text": 42 } and watch both directions flag INVALID
with text called out — that is the feedback
loop you keep for real endpoints, where the server's frames are the ones you
cannot predict.
Current limitations
Stated plainly, because they matter:
- No per-message scripts. You cannot yet run assertions or transformations on individual frames beyond schema validation.
- One connection per tab. Testing two sockets side by side means two tabs.
- Closing the tab or switching protocol disconnects. Navigating elsewhere in the app does not.
- The localhost tunnel does not relay the WebSocket upgrade. You cannot yet expose a local WebSocket endpoint through a tunnel URL — the tunnel carries plain HTTP (including SSE) only.
WebSocket requests save into collections like everything else, and the schemas you write for them are ordinary schemas — synced, versioned, and shared the same way.