SockJS - WebSocket support


Introduction

SockJS is a browser/server communication framework designed to provide a WebSocket-like programming model when native WebSocket support is unavailable or unreliable. SockJS isn’t supported as a standalone library. It’s only recognised as the transport behind a STOMP client, through StompOverSockJS. This extension supports the following WebSocket libraries:

Objects

Icon Metamodel name Description
TypeScript WebSocket Client Represents a WebSocket client connection identified by its URL
Link type From To Created when
callLink TypeScript Function / Method TypeScript WebSocket Client A function calls send() on a client connection — see filtering rule below
callLink TypeScript WebSocket Client TypeScript Function / Method A handler is registered on the client

A send link (callLink from a function to a WebSocket object) represents that the function actively pushes data to a WebSocket peer. In the call graph this makes the function a caller of the WebSocket server or client object, complementing the callee links that already show which functions receive messages from it.

Send link is created:

  • Function → WebSocket Client: the function sends a message over an outbound client connection (e.g. client.publish({...}) called from application code that is not itself a message handler).

Supported API methods

stomp/stompjs library

Client side

API method Object created / linked Link type
new Client({ webSocketFactory: () => new SockJS(url) }) (@stomp/stompjs) TypeScript WebSocket Client —
onConnect handler linked as callee of client callLink
onDisconnect handler linked as callee of client callLink
onStompError handler linked as callee of client callLink
onWebSocketError handler linked as callee of client callLink
onWebSocketClose handler linked as callee of client callLink
onUnhandledMessage handler linked as callee of client callLink
onUnhandledReceipt handler linked as callee of client callLink
onUnhandledFrame handler linked as callee of client callLink

stomp/rx-stomp package

Client side

API method Object created / linked Link type
`new RxStomp() + rxStomp.configure({ webSocketFactory brokerURL, … }) (@stomp/rx-stomp)` TypeScript WebSocket Client
stompErrors linked as callee of client callLink
webSocketErrors linked as callee of client callLink
unhandledMessage linked as callee of client callLink
unhandledReceipts linked as callee of client callLink
unhandledFrame linked as callee of client callLink

Example

When analyzing the following file

stomp-client.ts

import { Client } from '@stomp/stompjs';
import SockJS from 'sockjs-client';

let chatSub = null;

// Client docs: https://stomp-js.github.io/api-docs/latest/classes/Client.html
const client = new Client({
  // Use webSocketFactory (NOT brokerURL) when going through SockJS.
  // It must return a WebSocket-like object synchronously; SockJS uses http(s)://
  webSocketFactory: () => new SockJS('http://localhost:8080/stomp'),

  connectHeaders: {
    // login: 'guest', passcode: 'guest',
  },

  // Client.debug — verbose frame logging; remove in production
  debug: (msg) => console.debug('[STOMP]', msg),

  // Client.reconnectDelay — 0 disables automatic reconnect
  reconnectDelay: 5000,
  heartbeatIncoming: 10000,
  heartbeatOutgoing: 10000,

  // Fired after the CONNECTED frame. Always (re)subscribe here so that
  // subscriptions are restored after an automatic reconnect.
  onConnect: (frame) => {
    console.log('Connected:', frame.headers['server']);

    chatSub = client.subscribe(
      '/topic/chat',
      (message) => {
        const payload = JSON.parse(message.body);
        console.log(`${payload.from}: ${payload.text}`);
        // message.ack() / message.nack() if you subscribe with ack: 'client'
      },
      { id: 'chat-sub' } // optional stable subscription id
    );

    sendChat('alice', 'hello from the browser 👋');
  },

  onStompError: (frame) => {
    // Broker-level ERROR frame; connection is about to be closed
    console.error('Broker error:', frame.headers['message'], frame.body);
  },
  onWebSocketError: (evt) => console.error('WebSocket error', evt),
  onWebSocketClose: (evt) => console.warn('WebSocket closed', evt.code),
  onDisconnect: () => console.log('Disconnected (RECEIPT for DISCONNECT)'),
});

export function sendChat(from, text) {
  if (!client.connected) {
    console.warn('Not connected yet');
    return;
  }
  client.publish({
    destination: '/app/chat',
    body: JSON.stringify({ from, text }),
    headers: { 'content-type': 'application/json' },
  });
}

export async function stop() {
  chatSub?.unsubscribe();
  await client.deactivate(); // graceful DISCONNECT + close; stops reconnects
}

client.activate(); // starts connecting and keeps retrying per reconnectDelay

you will get the following result: