WebSocket API
Event Broker WebSocket
The sub, unsub and pub operations, the message delivery, and every reply and error, with frames.
Endpoint: wss://api.thuum.dev/api/{domain}/event/connect?token=…. The connection needs a key linked to
an Event Broker claim. Framing, refs and general errors are on WebSocket protocol.
Operations#
| Op | Fields | Flag | Reply |
|---|---|---|---|
sub | topic, ref? | S | sub:ok |
unsub | topic, ref? | — | unsub:ok |
pub | topic, type, data, ref? | P | pub:ok with id, ts |
The server pushes one more op, message, for each delivered event.
sub#
Subscribe to a topic and its whole subtree. Idempotent: subscribing twice is not an error and doesn't duplicate deliveries.
→ [{ "op": "sub", "topic": "orders", "ref": "1" }]
← [{ "op": "sub:ok", "topic": "orders", "ref": "1" }]From then on, every event published on orders or any orders:* topic arrives as a message. Events
published before the sub:ok are not delivered: read them from history.
unsub#
Stop receiving a topic's events. Idempotent, and needs no flag. Unsubscribing from orders doesn't
affect a separate subscription to orders:1042.
→ [{ "op": "unsub", "topic": "orders", "ref": "2" }]
← [{ "op": "unsub:ok", "topic": "orders", "ref": "2" }]pub#
Publish an event on exactly topic. The reply comes after the event is stored and broadcast, and
carries the server-generated id and ts.
→ [{ "op": "pub", "topic": "orders:1042", "type": "order.shipped", "data": { "carrier": "DHL" }, "ref": "3" }]
← [{ "op": "pub:ok", "topic": "orders:1042", "ref": "3", "id": "5bac385f-e73a-48c2-a505-8f1f8caa3c85", "ts": 1792590697447 }]Only topic, type and data are used: you cannot choose the id or the timestamp.
message#
One frame per delivered event, with the exact topic it was published on:
← [{ "op": "message", "id": "5bac385f-e73a-48c2-a505-8f1f8caa3c85", "topic": "orders:1042", "type": "order.shipped", "data": { "carrier": "DHL" }, "ts": 1792590697447 }]If the publishing connection is itself subscribed, it receives its message too, in addition to
pub:ok. The order between the two is not guaranteed.
Errors#
→ [{ "op": "pub", "topic": "orders:1042", "type": "bad type", "data": 1, "ref": "4" }]
← [{ "op": "pub:error", "topic": "orders:1042", "ref": "4", "code": "bad_request", "message": "type …" }]
→ [{ "op": "sub", "topic": "payroll", "ref": "5" }]
← [{ "op": "sub:error", "topic": "payroll", "ref": "5", "code": "forbidden", "message": "Missing S claim on topic" }]| Op | Possible codes |
|---|---|
sub | bad_request (invalid topic), forbidden |
unsub | bad_request (invalid topic) |
pub | bad_request, forbidden, internal |
With the client#
const socket = acme.eventBroker.connect();
socket.onMessage((event) => console.log(event));
await socket.ready;
await socket.sub('orders');
const { id, ts } = await socket.pub('orders:1042', 'order.shipped', { carrier: 'DHL' });
await socket.unsub('orders');
socket.close();Failed ops reject with EventBrokerSocketError, whose code is one of the codes above, or closed
if the connection dropped first. See Sockets.