null
null

Reputation: 1162

Use socket.io in expressjs routes instead of in main server.js file

I have express/nodejs api. I am adding socket.io feature to it. Currently all of my routes are in separate folders and I include them in server.js file and use them as app.use() function.

In server.js file, I also start the express server by listening to a particular port such as 3000 as below.

let server = app.listen(3000);

According to all google searches what I found is that I need to pass server variable to initialize socket.io like following.

let io = require('socket.io')(server);

Now the question is that since it needs this variable then how can I use socket.io in my routes files which are in different folder to emit and receive events from client?

UPDATE

in server.js file

let route = require('./routes/route');

let app = express();

let server = app.listen(3000);

console.log('Listening to port');

let io = require('socket.io')(server);

app.use('/api/1.0/events', route(io));

in route.js file

let express = require('express');

module.exports = (io) => {
    console.log('IO: ', io);
};

UPDATE 2

server.js file

let express = require('express');
let events = require('./routes/events');
let app = express();
let server = app.listen(3000);

let io = require('socket.io')(server);


app.use(function(request, response, next) {
    request.io = io;
    next();
});

app.use('/events', events);

events.js file

let express = require('express');

let Events = require('../models/events');

apiRoutes.post('/new', function(request, response) {
    let newEvent = new Events(request.body);

    newEvent.save((error, result) => {
        if (error) {
            response.json(error);
        } else {
            // console.log('ELSE');
            // request.io.on('connect', socket => {
                // console.log('LISTENING TO SOCKET...');

                request.io.on('EventCreated', data => {
                    console.log('DATA ON Server: ', data);
                });
            // });

            response.json({
                success: true,
                message: 'New event created'
            });
        }
    });
});

Upvotes: 40

Views: 25850

Answers (5)

Chinz
Chinz

Reputation: 917

For using a custom path with Socket.io, here is an implementation I tried :

const app = express();
const server = app.listen(port)

const io = new Server(server, {
  path: "/my-custom-path/"
});

On the frontend, it can be done like:

import { io } from "socket.io-client";
const socket = io('BACKEND_ENDPOINT', { path: '/my-custom-path/' });

Upvotes: 0

Philip Sopher
Philip Sopher

Reputation: 783

The middleware solution that worked for me —

index.js:

import express from 'express'
import mongoose from 'mongoose'
import cors from 'cors'
import http from 'http'
import { Server } from 'socket.io'
import staticRouter from './staticRouter.js'
import liveRouter from './liveRouter.js'

// Necessary for using 'require' for socket.io
import { createRequire } from 'module'
const require = createRequire(import.meta.url)


const startServer = async () => {
  
  const app = express()

  app.use(express.json())

  app.use('/static', staticRouter)

  app.use(cors())

  const server = http.createServer(app)

  const io = new Server(server, {
    cors: {
      origin: "origin-url",
      methods: ["GET", "POST", "PUT", "DELETE"],
    },
  })

  app.use(function(req, res, next) {
    req.io = io
    next()
  })

  app.use('/live', liveRouter)

  await mongoose.connect('your-mongo-endpoint') //Connecting to mongoose

  server.listen(3000)
}

startServer()

liveRouter.js:

import express from 'express'

import { liveConnection } from './live.js'

// Routes
const liveRouter = express.Router()

// Live Updates
liveRouter.route('/live-connection')
  .put(liveConnection)


export default liveRouter

and live.js:

export const liveEventConnection = async (req, res) => {

  console.log('req.io ->', req.io)

  // In any express route handler, you can use req.io.emit(...)
  
}

Upvotes: 0

Rizwan Amjad
Rizwan Amjad

Reputation: 442

Sharing my Solution that I've used

Another solution for this problem (that I actually used) is that we can make our io (socket.io object) object global.

Simply assign io to the global.io.

The io object is in index.js, after creating and setting up the io object simply do global (i-e global.io = io;), now this io object is accessible in any route that we are working within our project.

Upvotes: 6

jfriend00
jfriend00

Reputation: 707318

There are multiple ways to share the io variable with route files.

  1. When you require() in your route file, pass it the io variable as a constructor argument.

  2. Use app.set("io", io) so you can then use let io = app.get("io") in any file that has access to the app object.

  3. Create a middleware that puts the io object on every req object so you can access it from there any time.


Here's an example of passing it as a constructor argument to the router file:

let server = app.listen(3000);
let io = require('socket.io')(server);

// load other routers
app.use(require("./someRouterFile.js")(io));

// in someRouterFile.js
const express = require('express');

module.exports = function(io) {
    let router = express.Router()

    // define routes
    // io is available in this scope
    router.get(...)

    return router;
}

Here's an example of the app.set() scheme:

let server = app.listen(3000);
let io = require('socket.io')(server);
app.set("io", io);

Then, anywhere in your routes that you have access to the app object, you can get it with:

let io = app.get("io");

Here's an example of using a middleware to set the io object onto every req object so it's available from all routes.

let server = app.listen(3000);
let io = require('socket.io')(server);

// place this middleware before any other route definitions
// makes io available as req.io in all request handlers
app.use(function(req, res, next) {
    req.io = io;
    next();
});

// then in any express route handler, you can use req.io.emit(...)

Here's an example of using an argument to the module constructor without middleware:

// in mysocket.js
module.exports = (io) => {
    console.log('IO: ', io);
    io.on('connect', socket => {
       // handle various socket connections here
    });

    // put any other code that wants to use the io variable
    // in here


};

Then, in your main file:

let server = app.listen(3000);
let io = require('socket.io')(server);

// initialize my socketio module and pass it the io instance
require('./mysocket.js')(io);

Upvotes: 66

wrangler
wrangler

Reputation: 3576

In server.js:

module.exports.getIO = function(){
     return io;
}

In your route file:

var theServer = require('<path to server.js>');
var iovar = theServer.getIO(); //your io var

Upvotes: 5

Related Questions