Message Design
The foundations module taught you how to open a connection and push bytes both ways. But a connection that can carry anything tells you nothing about what those bytes mean. This module — Message Design — is where you stop sending raw text and start sending a protocol.
The socket is deliberately empty
Section titled “The socket is deliberately empty”Here is the thing nobody tells you when you first reach for a WebSocket: the API hands you send(data) and onmessage(event), and that is all. The connection is an opaque pipe. It will happily carry the string 'hi', a stringified JSON object, or a chunk of binary — and it has no opinion about any of them. There is no built-in notion of a “chat message”, a “request”, an “error”, or a “version”.
That emptiness is a feature, not an oversight. HTTP bakes in headers, status codes, methods, and content negotiation; a WebSocket bakes in almost nothing so that you can design exactly the conversation your application needs. The flip side is responsibility: whatever structure your messages have, you put it there.
flowchart TB
subgraph app["Your application"]
a1["chat lines · presence · edits · requests"]
end
subgraph proto["Your message protocol — THIS module"]
p1["type · payload · id · version · schema"]
end
subgraph ws["WebSocket transport"]
w1["send(text or binary) · onmessage"]
end
app --> proto --> ws
ws -- "opaque bytes" --> ws The middle layer is the one with no default. Designing it well is the difference between a protocol you can grow for years and one that becomes a tangle of special-cased strings.
What this module covers
Section titled “What this module covers”Five lessons, each adding one essential idea to your message design toolkit:
- Message Design (you are here) — why the socket is empty and you supply the meaning.
- Framing messages — WebSocket messages are already discrete, but you still need an application protocol; one JSON object per message.
- JSON vs binary — readable and universal JSON versus compact binary formats like MessagePack, Protobuf and CBOR, and when each wins.
- Request/response over WebSocket — the socket is message-oriented, not request/reply; you add a correlation
idto match an answer to its question. - Schemas and versioning — a message envelope, validating what arrives, and evolving the protocol without breaking older clients.
A first structured message
Section titled “A first structured message”Below is the smallest possible step up from sending plain text: sending a JSON object and parsing it on the other side. It runs in your browser against an in-page echo socket that uses the real WebSocket API — same onopen, onmessage, send, close — so there is no server to start. In a real app, only the first line changes to new WebSocket('wss://your-server').
Notice that the moment we send an object instead of a bare string, the receiver can ask meaningful questions: what kind of message is this? who sent it? When?
The socket carried text both ways and never once cared that it was JSON. The structure — type, from, text — exists only because we agreed on it and put it there. Every lesson that follows refines that agreement.