WebSocket Connection

The Enhub API provides a WebSocket endpoint for receiving real-time updates about your optimization scans. This guide shows you how to connect to the WebSocket server and handle status updates.

Connecting to the WebSocket

To connect to the WebSocket server, use the native WebSocket API available in all modern browsers and Node.js environments. The WebSocket endpoint is available at the /ws path.

Establishing a connection

// Replace with your actual API base URL
const baseUrl = 'https://api.enhub.nl';
const wsUrl = baseUrl.replace(/^http/, 'ws') + '/ws';

// Create WebSocket connection
const ws = new WebSocket(wsUrl);

// Handle connection open
ws.onopen = () => {
  console.log('Connected to Enhub WebSocket');
};

// Handle errors
ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

// Handle disconnection
ws.onclose = (event) => {
  console.log('Disconnected:', event.code, event.reason);
};

Subscribing to Scan Updates

Once connected, you can subscribe to updates for specific scans by sending a subscription message with the scan's run_uuid.

Subscribe to scan updates

ws.onopen = () => {
  console.log('Connected to Enhub WebSocket');
  
  // Subscribe to a specific scan
  const subscribeMessage = {
    type: 'subscribe',
    run_uuid: 'your-scan-uuid-here',
  };
  
  ws.send(JSON.stringify(subscribeMessage));
};

Receiving Status Updates

After subscribing, you'll receive real-time updates about your scan's progress and status. Handle incoming messages by parsing the JSON data.

Handle status updates

ws.onmessage = (event) => {
  try {
    const message = JSON.parse(event.data);
    
    switch (message.type) {
      case 'subscribed':
        console.log('Successfully subscribed:', message.data);
        break;
        
      case 'status_update':
        const { progression, status } = message.data;
        
        console.log('Scan progress:', progression + '%');
        console.log('Scan status:', status);
        
        // Update your UI with the progress
        if (progression !== undefined) {
          updateProgressBar(progression);
        }
        
        // Handle different scan statuses
        switch (status) {
          case 'calculating':
            console.log('Scan is processing...');
            break;
            
          case 'optimal':
            console.log('Scan completed! Fetching results...');
            handleScanComplete(message.data);
            // Server will disconnect automatically
            break;
        }
        break;
        
      case 'unsubscribed':
        console.log('Unsubscribed from scan');
        break;
        
      default:
        console.log('Unknown message type:', message.type);
    }
  } catch (error) {
    console.error('Failed to parse message:', error);
  }
};

function updateProgressBar(progress) {
  // Your UI update logic here
  document.getElementById('progress-bar').style.width = progress + '%';
}

function handleScanComplete(data) {
  // Handle scan completion
  console.log('Scan completed with data:', data);
}

Message Types

Client to Server

  • Name
    type
    Type
    string
    Description

    The message type. Use "subscribe" to subscribe to updates or "unsubscribe" to stop receiving updates.

  • Name
    run_uuid
    Type
    string
    Description

    The unique identifier for the scan you want to subscribe to or unsubscribe from.

Server to Client

All server messages include these fields:

  • Name
    type
    Type
    string
    Description

    The message type. Can be "subscribed", "unsubscribed", or "status_update".

  • Name
    run_uuid
    Type
    string
    Description

    The scan UUID this message relates to.

  • Name
    data
    Type
    object
    Description

    The message payload containing status information or confirmation messages.

Status Update Data

  • Name
    progression
    Type
    number
    Description

    Scan completion percentage (0-100).

  • Name
    currentProgress
    Type
    number
    Description

    Alternative field for scan completion percentage.

  • Name
    status
    Type
    string
    Description

    Current scan status. See Scan Status Values below for all possible values.

Scan Status Values

The status field in status updates indicates the current state of your optimization scan. Here are the possible values:

  • Name
    calculating
    Type
    status
    Description

    Scan is processing — The optimization algorithm is actively running. Your scan is being processed and you should continue to receive progress updates. Do not call the results endpoint yet.

  • Name
    optimal
    Type
    status
    Description

    Scan completed successfully — The optimization has finished and results are ready. When you receive this status, you can now call the GET /v1/scan endpoint with your run_uuid to retrieve the complete scan results. The WebSocket connection will automatically disconnect after sending this final update.

Unsubscribing

To stop receiving updates for a scan, send an unsubscribe message:

Unsubscribe from scan updates

const unsubscribeMessage = {
  type: 'unsubscribe',
  run_uuid: 'your-scan-uuid-here',
};

ws.send(JSON.stringify(unsubscribeMessage));

Complete Example

Here's a complete example showing how to connect, subscribe, receive updates, and handle disconnection:

Complete WebSocket example

class EnhubWebSocket {
  constructor(baseUrl, runUUID) {
    this.baseUrl = baseUrl;
    this.runUUID = runUUID;
    this.ws = null;
  }
  
  connect() {
    const wsUrl = this.baseUrl.replace(/^http/, 'ws') + '/ws';
    this.ws = new WebSocket(wsUrl);
    
    this.ws.onopen = () => {
      console.log('Connected to Enhub WebSocket');
      this.subscribe();
    };
    
    this.ws.onmessage = (event) => {
      this.handleMessage(event);
    };
    
    this.ws.onerror = (error) => {
      console.error('WebSocket error:', error);
    };
    
    this.ws.onclose = (event) => {
      if (event.wasClean) {
        console.log('Connection closed cleanly:', event.code);
      } else {
        console.log('Connection closed unexpectedly:', event.code);
      }
    };
  }
  
  subscribe() {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      const message = {
        type: 'subscribe',
        run_uuid: this.runUUID,
      };
      this.ws.send(JSON.stringify(message));
    }
  }
  
  handleMessage(event) {
    try {
      const message = JSON.parse(event.data);
      
      switch (message.type) {
        case 'subscribed':
          console.log('Subscribed to scan:', this.runUUID);
          this.onSubscribed(message.data);
          break;
          
        case 'status_update':
          console.log('Status update:', message.data);
          this.onStatusUpdate(message.data);
          break;
          
        case 'unsubscribed':
          console.log('Unsubscribed from scan');
          this.onUnsubscribed(message.data);
          break;
      }
    } catch (error) {
      console.error('Failed to parse message:', error);
    }
  }
  
  // Override these methods in your implementation
  onSubscribed(data) {
    console.log('Successfully subscribed:', data);
  }
  
  onStatusUpdate(data) {
    console.log('Progress:', data.progression + '%');
    
    if (data.status === 'optimal') {
      console.log('Scan completed!');
      // Server will disconnect automatically
    }
  }
  
  onUnsubscribed(data) {
    console.log('Unsubscribed:', data);
  }
  
  unsubscribe() {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      const message = {
        type: 'unsubscribe',
        run_uuid: this.runUUID,
      };
      this.ws.send(JSON.stringify(message));
    }
  }
  
  disconnect() {
    if (this.ws) {
      this.unsubscribe();
      this.ws.close();
    }
  }
}

// Usage
const socket = new EnhubWebSocket('https://api.enhub.nl', 'your-scan-uuid');

// Override handlers
socket.onStatusUpdate = (data) => {
  document.getElementById('progress').textContent = data.progression + '%';
  
  if (data.status === 'optimal') {
    alert('Scan completed!');
  }
};

// Connect
socket.connect();

// Later, when done
socket.disconnect();

Auto-Disconnect on Completion

When a scan reaches completion (status: "optimal"), the server will:

  1. Send a final status update with the complete status
  2. Automatically disconnect all clients subscribed to that scan
  3. Close the WebSocket connection with code 1000 (normal closure)

You don't need to manually unsubscribe when a scan completes - the server handles this automatically to clean up resources.

Handling auto-disconnect

ws.onclose = (event) => {
  if (event.code === 1000) {
    console.log('Connection closed normally - scan may be complete');
  } else {
    console.log('Connection closed with code:', event.code);
  }
};

Best Practices

  • Error Handling: Always implement error handlers to catch connection issues
  • Reconnection: Consider implementing automatic reconnection for production use
  • Message Validation: Validate incoming messages before processing
  • Resource Cleanup: Always close the WebSocket connection when done
  • Multiple Scans: You can subscribe to multiple scans using the same connection

Browser Support

The native WebSocket API is supported in all modern browsers:

  • Chrome 4+
  • Firefox 4+
  • Safari 5+
  • Edge 12+
  • Opera 10+

For Node.js environments, use the ws package or any WebSocket client library.

Was this page helpful?