NestJS WebSocket Message Format

171 views Asked by At

I am trying to implement a WebSocket server with ws (not socket.io) and based on these answers from StackOverflow, WebSocket messages must be in the format {event: "eventname', data: {data}} :

SubcribeMessage decorator doesn't trigger on event 'message'

Messages not reaching handler while using WebSocket and nestjs

I was wondering if there is a way to bypass this and/or if there is any official documentation regarding this.

Since the messages I am currently receiving from the server are in a fixed format, it would be nice to know if there is any more info on this. Thank you for reading.

1

There are 1 answers

1
Jacob Murphy On

I had a similar issue where I was getting WebSocket messages from Twilio when streaming call audio but Twilio doesn't use the ws package's format. My solution was to extend the WsAdapter and overwrite the bindMessageHandler function to ensure the data field was present.

// custom-ws-adapter.ts
import { MessageMappingProperties } from '@nestjs/websockets/gateway-metadata-explorer';
import { EMPTY, Observable } from 'rxjs';
import { WsAdapter } from '@nestjs/platform-ws';

export class CustomWsAdapter extends WsAdapter {
  // taken from https://github.com/nestjs/nest/blob/master/packages/platform-ws/adapters/ws-adapter.ts
  public bindMessageHandler(
    buffer: any,
    handlers: MessageMappingProperties[],
    transform: (data: any) => Observable<any>,
  ): Observable<any> {
    try {
      const message = JSON.parse(buffer.data);
      const messageHandler = handlers.find(
        handler => handler.message === message.event,
      );
      const { callback } = messageHandler;

      // BEGIN MODIFIED CODE
      // This is needed since the ws library expects {event: string; data: any} formatting
      // but Twilio's call streams don't have the data field
      if (!message.data) {
        message.data =  { ...message, event: undefined }
      }
      // END MODIFIED CODE

      return transform(callback(message.data, message.event));
    } catch {
      return EMPTY;
    }
  }
}

// in main.ts
const app = await NestFactory.create(AppModule);
app.useWebSocketAdapter(new CustomWsAdapter(app))