Documentation menu

Testing WebSocket APIs

Connect to ws:// and wss:// endpoints in SchemaClient, send JSON frames, follow the live message log, and validate every frame in both directions against a schema.

Updated

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.

Frequently asked questions

How do I test a WebSocket API without writing code?

Use a client that speaks WebSocket natively. In SchemaClient, switch the request to WS mode, enter the ws:// or wss:// URL, hit Connect, and type JSON messages into the composer. Every sent and received frame appears in a live log with timestamps — no browser console scripting required.

Can I send custom headers or auth on a WebSocket connection?

Yes — on the handshake. WebSocket auth happens during the initial HTTP upgrade request, so headers, bearer tokens, basic auth, and header-placed API keys are all sent when the connection opens. Browsers cannot set custom WebSocket headers, which is exactly why a native client helps here.

How do I validate WebSocket messages against a schema?

Link a schema that declares the message shapes with @websocket plus Send and Receive blocks. SchemaClient checks every JSON frame in both directions as it happens and badges each one VALID or INVALID, with field-level errors on the invalid ones.