Search code examples
node.jstypescriptexpressexpress-ws

TypeError: router.ws is not a function express-ws typescript


I'm trying to create a websocket endpoint for router in my express app with express-ws module but getting an error.

Here is an entry point of the server index.ts:

import express from 'express';
import expressWs from 'express-ws';
import * as dotenv from 'dotenv';
import cookieParser from 'cookie-parser';
import cors from 'cors';
import mongoose from 'mongoose';
import auth from './routes/auth.route.js';
import data from './routes/data.route.js';
import user from './routes/user.route.js';
import logger from './utils/logger.js';
import errorMiddleware from './middlewares/error.middleware.js';

dotenv.config()

const PORT = process.env.PORT;
const ORIGIN = process.env.DOMAIN_URL;

const app = expressWs(express()).app;

const corsOptions = {
    origin: ORIGIN,
    credentials: true
}

app.use(express.json());
app.use(cookieParser());
app.use(cors(corsOptions));

app.use('/api/auth', auth);
app.use('/api/data', data);
app.use('/api/user', user);

app.use(errorMiddleware);

async function start() {
    try {
        await mongoose.connect(process.env.DB_URL)
    } catch (err) {
        logger.error(`An error occured while connecting to database: ${err}`)
    }
    app.listen(PORT, () => {
        console.log(`Server started on port ${PORT}`);
    });
}

start();

And here is data.route.ts:

import express from 'express';
import dataController from '../controllers/data.controller.js';
import authMiddleware from '../middlewares/auth.middleware.js';

const router = express.Router();

router.use(authMiddleware);

...
router.ws('/ws/tradebars', (ws, req) => {}); // TypeError: router.ws is not a function

export default router;

Solution

  • I had a similar issue. Problem is you're calling the ws function on router before you've called this line (because of the import): const app = expressWs(express()).app;

    A possible solution is to wrap the ws call in a function that you can export, and call at a later point. For example (data.route.ts):

    ...
    export const mountRouter = () => {
      router.ws('/ws/tradebars', (ws, req) => {}); 
    }
    export default router;
    

    And then in your index.ts

    import data, {mountRouter} from './routes/data.route.js'
    
    const app = expressWs(express()).app;
    mountRouter()
    
    app.use('/api/data', data);