2

I'm setting up a WebSocket server on my NestJS backend, and when I try subscribing on the default 'message' event type, the method handleMessage() doesn't get triggered.

The listenForMessages() method however works (which is triggered after the init of the server). Does anyone know why the decorator @SubscribeMessage('message') doesn't work?

@WebSocketGateway()
export class AppWebsocketGateway implements OnGatewayInit, OnGatewayDisconnect {
  private clientIds = new Map<string, string>();
  // @ts-ignore
  @WebSocketServer() server: Server;
  private logger: Logger = new Logger('WebsocketGateway');

  constructor(private readonly evseService: EvseService) {
  }

  listenForMessages() {
    this.server.on('connection', (ws) => {
      ws.on('message', (e) => {
        console.log(e);
      });
    });
    this.logger.log('message received');
  }


  @SubscribeMessage('message')
  handleMessage(@ConnectedSocket() client: any, payload: any): void {
    this.logger.log('I received a message from the client!');
    this.server.emit('msgToClient', payload);
  }

  afterInit(server: Server) {
    this.logger.log('Init');
    this.listenForMessages();
  }

  handleDisconnect(@ConnectedSocket() client: any) {
    this.logger.log(`Client disconnected: ${client.id}`);
  }
}
Ken White
  • 123,280
  • 14
  • 225
  • 444

1 Answers1

5
//@SubscribeMessage('message') will look for the message that are in the format :
{
  event:'message',
  data: {someData} // Whatever in the data field will be the payload in 
                   //handleMessage()
}

// Another example 
// @SubscribeMessage('get_profile') will look for messages in the format : 

{
  event:'get_profile',
  data: {someData} // Whatever in the data field will be the payload in 
                   //handleMessage()
}

So why does @SubscribeMessage('message') need such a format? Well, for leveraging NestJS features such as interceptors, pipes etc. If you implement such a format for the incoming messages (events), in the future, you would not have to change the handler logic even if you change the library to socket.io or μWebsocket.js or your own implementation for websockets. You just need to implement your own custom websocket adapter.

In short, NestJS makes sure that your code says the same even if the underlying technology changes.

The listenForMessages() directly attaches a listener on the server. This is a library specific approach and you would need to change all the listener logic if you decide to change the library to: say, socket.io.

ws.on('message', callback);, will log whatever the socket sends (as per your code in listenForMessages()), disregarding the format,ie: you can send a string, buffer, JSON, etc.. but for @SubscribeMessage(<event>) it has to be in the format :

{
event : <event>,
data : <any>, // Can be string, number, object, buffer, whatever you want
}

ws - is a socket which is connected on the server.

SPS
  • 733
  • 1
  • 8
  • 16
  • Thanks for the extensive answer, do you know to which 'eventType' I should listen then in `@SubscribeMessage()`. Because my WSS clients do not specify any eventType, it's just send out by `ws.send(dataGoesHere)`. I thought the default eventType in that case was 'message'. – Tom De Kooning Apr 29 '21 at 07:25
  • 2
    As I said before, you should have a format when sending data to the gateway. So you should send stringified version of : ```{event:'message',date:{sender:1,content:'hello'}}``` from the front end. This will trigger the ```@SubscribeMessage('message')``` and the ```payload``` will be ```{sender:1,content:'hello'}``` – SPS Apr 29 '21 at 08:00
  • Thanks for confirming, unfortunately I have no control over the clients as I'm developing a WebSocket Server to handle clients that operate through a certain protocol. This is the right answer though so I'll check it! – Tom De Kooning Apr 29 '21 at 14:11
  • If you have no control over the data being sent from the front-end, I suggest that you isolate the websocket section, since you'll be using the library specific techniques and API's. It will be a great relief when you have to refactor or add a new feature. – SPS Apr 29 '21 at 15:42
  • 1
    Is it documented somewhere? On the [official documentation](https://docs.nestjs.com/websockets/gateways), they say that you can send your message as such: `socket.emit("eventName", someData);`, there is no indication that you need to send the event name as well in the data like `socket.emit("eventName", { event: "eventName", data: someData });` and I'm a little bit confused between your answer and the official documentation. Can you please add some references? – Amin NAIRI Apr 16 '23 at 12:49