FDD Story Get Started Tutorial Docs Motivation Download GitHub

WebSockets

ARO provides built-in WebSocket support for real-time bidirectional communication. WebSocket connections are established via HTTP Upgrade on the same port as the HTTP server, making it easy to add live updates to web applications.

Why WebSockets?

Unlike traditional HTTP request-response cycles, WebSocket enables persistent connections where both server and client can push data at any time. This is essential for:

WebSocket Events

WebSocket lifecycle is managed through three event types:

Event Handler Name Contains Triggered When
Connect "Connect" Client completes WebSocket handshake
Message "Message" Client sends a text message
Disconnect "Disconnect" Connection closes

Event Handlers

Handle WebSocket events using the WebSocket Event Handler business activity pattern:

Connection Handler

(Handle WebSocket Connect: WebSocket Event Handler) {
    Extract the <connection-id> from the <event: id>.
    Log "WebSocket client connected" to the <console>.
    Return an <OK: status> for the <connection>.
}

The event object provides:

Message Handler

(Handle WebSocket Message: WebSocket Event Handler) {
    Extract the <message> from the <event: message>.
    Extract the <connection-id> from the <event: connectionId>.
    Log <message> to the <console>.
    Return an <OK: status> for the <message>.
}

Disconnection Handler

(Handle WebSocket Disconnect: WebSocket Event Handler) {
    Extract the <connection-id> from the <event: connectionId>.
    Log "WebSocket client disconnected" to the <console>.
    Return an <OK: status> for the <disconnection>.
}

Broadcasting Messages

Send a message to all connected WebSocket clients:

Broadcast the <message> to the <websocket>.

Messages are automatically serialized to JSON if they are objects. This is commonly used when posting new data via HTTP that should be pushed to all connected clients.

Complete Example: Real-Time Chat

Project Structure

WebChat/
├── openapi.yaml      # API contract
├── main.aro          # Application lifecycle
├── api.aro           # HTTP route handlers
├── websocket.aro     # WebSocket event handlers
└── templates/
    └── index.html    # Chat UI

main.aro

(Application-Start: Web Chat) {
    Log "Starting Web Chat..." to the <console>.
    Start the <http-server> with {}.
    Keepalive the <application> for the <events>.
    Return an <OK: status> for the <startup>.
}

api.aro

(postMessage: Web Chat API) {
    Extract the <body> from the <request: body>.
    Extract the <text: message> from the <body>.
    Create the <message: Message> with {
        message: <text>,
        createdAt: <now>
    }.
    Store the <message> into the <message-repository>.

    (* Broadcast to all WebSocket clients *)
    Broadcast the <message> to the <websocket>.

    Return a <Created: status> with <message>.
}

Client JavaScript

// Connect to WebSocket
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const ws = new WebSocket(`${protocol}//${location.host}/ws`);

ws.onopen = () => console.log('Connected');

ws.onmessage = (event) => {
    const message = JSON.parse(event.data);
    displayMessage(message);
};

ws.onclose = () => {
    console.log('Disconnected, reconnecting...');
    setTimeout(connect, 3000);
};

WebSocket Path

By default, WebSocket connections are accepted on /ws:

const ws = new WebSocket('ws://localhost:8080/ws');

Best Practices


← TCP Sockets | Templates →