fastify-websocket icon indicating copy to clipboard operation
fastify-websocket copied to clipboard

Full declaration syntax is not typed correctly for `websocket: true`

Open yakovenkodenis opened this issue 1 year ago • 7 comments

Prerequisites

  • [X] I have written a descriptive issue title
  • [X] I have searched existing issues to ensure the bug has not already been reported

Fastify version

5.2.0

Plugin version

11.0.1

Node.js version

22.12

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

Sonoma 14.5

Description

It seems that the full declaration syntax is not supported by @fastify/websocket types.

Also, when the wsHandler property is set, the behaviour is the following:

  • the handler property is still required and typescript throws error when it is not in place;
  • when the handler property is also set, the ws connection is handled by the handler property while wsHandler is ignored.

Is this the expected behaviour?

import Fastify from 'fastify';
import FastifyWebsocket from '@fastify/websocket';

const app = Fastify();
app.register(FastifyWebsocket);

app.route({
  method: 'GET',
  url: '/',
  websocket: true,
  handler: async (websocket, request) => {
    // 'websocket' is typed as FastifyRequest, not WebSocket
    // 'request' is typed as FastifyReply, not FastifyRequest
  },
});

app.route({
  method: 'GET',
  url: '/',
  websocket: true,
  wsHandler: (socket, request) => {
    console.log('WS'); // not printed
  },
  handler: (socket, request) => {
    console.log(socket.constructor.name === 'WebSocket'); // prints true (when executing "new WebSocket('ws://localhost:3000/')" in the browser)
  },
});

Somewhat related issue: https://github.com/fastify/fastify-websocket/issues/133

Expected Behavior

  1. The full declaration syntax (RouteOptions type) is typed correctly.
  2. wsHandler is executed for ws connection when both handler and wsHandler are defined.

yakovenkodenis avatar Dec 18 '24 15:12 yakovenkodenis

the handler property is still required and typescript throws error when it is not in place;

Not tested yet.

when the handler property is also set, the ws connection is handled by the handler property while wsHandler is ignored.

From your example, it is expected behavior because websocket: true option means to use handler as the websocket handler. You should remove the websocket property in the route option.

climba03003 avatar Dec 19 '24 09:12 climba03003

I am facing this issue too. Even when I make a WebSocket request, the wsHandler is never reached.

{
  method: 'GET',
  url: '/ws/logs',
  wsHandler: (socket, request) => {
    console.log('WS'); // This is never printed
  },
  handler: (socket, request) => {
    console.log(socket.constructor.name); 
    // Prints "_Request" when executing "new WebSocket('ws://localhost:3000/ws/logs')" in the browser
  },
}

My route is defined using the full declaration syntax.

Anything I’m missing?

rohilsaraf97 avatar Jan 07 '25 11:01 rohilsaraf97

Nah, same here. Something is wrong, it always hits handler:

Megamannen avatar Jan 15 '25 06:01 Megamannen

Ok, this is probably caused by a separate issue. You can do this and it will work:

import Fastify from 'fastify';
import FastifyWebsocket from '@fastify/websocket';

const app = Fastify();
app.register(FastifyWebsocket);

app.register(async function (app) {
  app.route({
    method: 'GET',
    url: '/',
    wsHandler: (socket, request) => {
      console.log('WS'); // not printed
    },
    handler: (socket, request) => {
      console.log(socket.constructor.name === 'WebSocket'); // prints true (when executing "new WebSocket('ws://localhost:3000/')" in the browser)
    },
  });
})

Megamannen avatar Jan 15 '25 06:01 Megamannen

I am facing this issue too. Even when I make a WebSocket request, the wsHandler is never reached.

{ method: 'GET', url: '/ws/logs', wsHandler: (socket, request) => { console.log('WS'); // This is never printed }, handler: (socket, request) => { console.log(socket.constructor.name); // Prints "_Request" when executing "new WebSocket('ws://localhost:3000/ws/logs')" in the browser }, } My route is defined using the full declaration syntax.

Anything I’m missing?

I don't know why, but if you enter websocket:false in the ‘route’ object or don't send it at all, the wsHandler function works. If you set it to true, the handler function works.

@fastify/websocket version: 10.0.1 fastify version: 4.28.1

Fatihkrty avatar Feb 04 '25 12:02 Fatihkrty

I had this problem and I just figured it out, the clue was in the documentation:

When using @fastify/websocket, it needs to be registered before all routes in order to be able to intercept websocket connections to existing routes and close the connection on non-websocket routes.

Need to do it likem this

import websocket from '@fastify/websocket'

const server = fastify();

//register websocket server
server.register(websocket);

// then register routes
server.register(routes)

dotenv.config(); // load dotenv

then it will work correctly:

Image

ElHex avatar Mar 14 '25 06:03 ElHex

you need to install ws types

pnpm add -D @types/ws
npm i @types/ws -D

rnnc avatar May 26 '25 17:05 rnnc