skip to content

Why adopt a published WebSocket subprotocol such as STOMP or MQTT instead of inventing your own JSON message envelope?

level: middleimportance: must knowfreq 48%

answer

  1. frames, then nothing above them
  2. someone writes the envelope regardless
  3. acknowledgement and errors, specified or not
  4. a name makes the choice visible
  5. inherited grammar is the price

basics

~20 s

A published subprotocol hands you a specified message grammar with acknowledgement and error semantics somebody else designed, documented and implemented twice. An ad-hoc envelope means you own all of that, usually without writing it down.

solid answer

~50 s

The WebSocket protocol gives you framed text and binary messages and nothing above them — no request/response pairing, no acknowledgement, no error shape, no subscription model. Something has to supply those, and an ad-hoc envelope means your team specifies, documents, versions and debugs them itself, typically in a wiki page that drifts. Adopting a published subprotocol such as STOMP or MQTT carried over WebSocket buys a grammar that is already specified, already has acknowledgement and error semantics, and already has independent implementations a client team can use without reading your code. The cost is real: you inherit the whole protocol, including the parts your product will never use, and its model may not fit your domain. The honest middle ground is to still negotiate a versioned name for your own envelope, so the handshake records which reading is in force.

code

json · 5 lines
json
{
  "type": "cue.go",
  "id": "8f31",
  "payload": { "cue": 112, "fade": 3.5 }
}

go deeper

for a junior

Remember that a WebSocket delivers messages and defines nothing about what is in them. Whatever structure your messages have was designed by someone — recognising that there is a layer above the frames is the point.

for a middle

Argue both directions: what a specified grammar gives you in acknowledgement, error shape and independent clients, against the weight of a protocol whose model may not fit your domain.

for a senior

Demonstrate the operational habit — a written grammar, a versioned negotiated name, an explicit rule for unknown message kinds — and be able to name the incident shape that follows when those are missing.

for a principal

The call is organisational as much as technical: a published protocol is a contract with teams you will never meet, while a house envelope is a contract only your team can honour, and only while it stays your team.

## What the socket does not give you Once a WebSocket connection is open, the protocol offers exactly this: messages that are text or binary, delivered in order, in either direction, with a liveness probe and a close handshake. That is the whole contract. There is no correlation between a message and a reply, no acknowledgement, no defined error shape, no subscription or unsubscription, no notion of a destination or a stream inside the one connection. Every real application needs several of those. So the question is never *whether* there will be an application protocol above the frames — there always is — but whether it is one somebody specified, or one that accumulated. ## What a published subprotocol hands you - **A specified grammar.** The set of message kinds is fixed and written down, with which fields are required on each. - **Acknowledgement and error semantics.** How a receiver says "got it", how a sender learns it did not, and what an error message contains — the three things ad-hoc envelopes almost always add late, under incident pressure. - **A name for the handshake.** Because it has a registered subprotocol name, the choice is visible in `Sec-WebSocket-Protocol` and is negotiated per connection rather than assumed. - **Independent implementations.** A team on a platform you did not plan for can pick up an existing client instead of reimplementing your wiki page. - **A reviewer's shared vocabulary.** Arguing about whether a message should be acknowledged is cheaper when the answer is in a specification rather than in a colleague's memory. STOMP is the compact example: a small set of text frames — connect, send, subscribe, acknowledge, error — each with specified headers, designed to sit directly on a stream like a WebSocket. MQTT is the other common one, carried over WebSocket rather than its own TCP binding, bringing a topic-based subscription model and defined delivery-quality levels. Neither is a library; both are published specifications, and either can be implemented from the document. ## What it costs | Adopting a published subprotocol | Inventing an envelope | |---|---| | You inherit the whole grammar, used or not | You carry only what you need | | Its model may not match your domain | It matches your domain exactly, today | | Debugging goes through one more encoding layer | Payloads are readable straight off the wire | | Behaviour is settled by a document | Behaviour is settled by whoever is on call | | Client teams can read a specification | Client teams read your source | The first two rows are the honest objection. If your product sends four message kinds down one socket and both ends ship from the same repository on the same day, a published protocol can be more ceremony than the problem deserves — and its model can actively fight you, for example when a publish/subscribe shape has to carry a request that expects one reply. ## The failure mode that actually bites The defect is rarely "we chose our own envelope". It is choosing one **without noticing that you chose**, which produces three symptoms in order: 1. Messages grow a `type` field, then a correlation field, then an ack field, each added by a different person with a different convention. 2. Nobody can say what happens to a message whose type the receiver does not recognise, because that was never decided. 3. A second client platform arrives, reimplements the envelope from a reading of the server code, and gets the edge cases wrong in ways that only show under load. ## If you do roll your own, do these three things 1. **Write it down as a specification**, not as comments: the message kinds, the required fields, the error shape, and what a receiver does with an unknown kind. 2. **Negotiate a versioned, domain-scoped name** for it in the opening handshake, so every connection records which reading it agreed to and skew is visible at connect time. 3. **Decide acknowledgement up front.** Whether a sender ever learns that a message was processed is a protocol decision, and retrofitting it later means changing both ends at once. An interviewer asking this is checking one instinct: that you recognise there is an application protocol above the socket whether or not you designed it deliberately, and that you can argue the trade rather than reciting one side of it.

  • When is an ad-hoc envelope the right call?
    When the message set is small and stable, both ends ship together from one repository, and no third party will ever implement a client. Even then, write the grammar down and negotiate a versioned name for it, so the decision survives the people who made it.
  • Does adopting a published subprotocol change anything about the WebSocket handshake itself?
    Only the value of one field. The client offers the protocol's registered name in `Sec-WebSocket-Protocol` and the server echoes it on the 101 response. The frames, the close handshake and the liveness probe are unchanged — the subprotocol lives entirely in the message payloads.
  • Your envelope needs request/response pairing over a socket that has none. What must you specify?
    A correlation identifier the requester generates and the responder copies back, a rule for what happens when no reply arrives, and a rule for a reply whose correlation value matches nothing outstanding. The socket delivers messages in order but pairs nothing, so all three are yours to define.

saying these in an interview costs you the question

  • Says the WebSocket protocol already provides request/response pairing
  • Claims an ad-hoc envelope has no protocol, only messages
  • Thinks a published subprotocol requires a specific vendor's client
  • Assumes acknowledgement can be added later without changing both ends
  • Believes choosing a subprotocol changes the frames on the wire