Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

express.js 4 and sockets with express router

I'm trying to create a really simple node API using express.js 4 but I need a few 'realtime' events for which I added socket.io. I'm fairly new to both so I'm likely missing something basic but I can't find good docs/tuts on this.

In the express app (created with the express generator) I have something like this based on simple examples and project docs that I read. This works OK and from client apps, I can send/receive the socket events:

var express = require('express');
var path = require('path');
var logger = require('morgan');
var api = require('./routes/api');
var app = express();
var io = require('socket.io').listen(app.listen(3000));

app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/api', api);

io.sockets.on('connection', function (socket) {
    console.log('client connect');
    socket.on('echo', function (data) {
        io.sockets.emit('message', data);
    });
});


// error handlers omitted

module.exports = app;

but I want to use the sockets from my API routes (in the ./routes/api.js file that I 'require' above). For example, someone might use the API to PUT/POST a resource and I want that broadcast to connected socket.io clients.

I cannot see how to use the 'io' variable or organise the code currently in the io.sockets.on('connection' ... function inside express routes. Here's the ./routes/api.js file:

var express = require('express');
var router = express.Router();
var io = ???;

router.put('/foo', function(req, res) {
    /* 
      do stuff to update the foo resource 
      ...
     */

    // now broadcast the updated foo..
    io.sockets.emit('update', foo); // how?
});

module.exports = router;
like image 215
darrend Avatar asked Mar 29 '15 21:03

darrend


People also ask

Can you use socket IO with Express?

We are going to use Express and Socket.IO side by side. Socket.IO does not use HTTP like a web application. It is event based, not request based. This means that Socket.IO will not interfere with Express routes that we have set up, and that's a good thing.

What is Router () in Express?

The express. Router() function is used to create a new router object. This function is used when you want to create a new router object in your program to handle requests. Multiple requests can be easily differentiated with the help of the Router() function in Express. js.

How does routing work in Express JS?

A route method is derived from one of the HTTP methods, and is attached to an instance of the express class. The following code is an example of routes that are defined for the GET and the POST methods to the root of the app. Express supports methods that correspond to all HTTP request methods: get , post , and so on.


4 Answers

One option is to pass it in to req object.

app.js:

var express = require('express'); var path = require('path'); var logger = require('morgan'); var api = require('./routes/api'); var app = express(); var io = require('socket.io').listen(app.listen(3000));  app.use(logger('dev')); app.use(express.static(path.join(__dirname, 'public')));  io.sockets.on('connection', function (socket) {     console.log('client connect');     socket.on('echo', function (data) {         io.sockets.emit('message', data);     }); });  // Make io accessible to our router app.use(function(req,res,next){     req.io = io;     next(); });  app.use('/api', api);  // error handlers omitted  module.exports = app; 

./routes/api.js:

var express = require('express'); var router = express.Router();  router.put('/foo', function(req, res) {     /*        do stuff to update the foo resource        ...      */      // now broadcast the updated foo..     req.io.sockets.emit('update', foo);  });  module.exports = router; 
like image 149
platlas Avatar answered Oct 16 '22 05:10

platlas


I've modified your files a little bit, may you check if it works?

You can pass the io you've defined to your routes like below;

require('./routes/api')(app,io);  

I didn't test the Socket.IO parts but there is no syntax error and routes also working.

server.js file:

var express = require('express'); var app = express(); var path = require('path'); var logger = require('morgan');  var io = require('socket.io').listen(app.listen(3000));   app.use(logger('dev')); app.use(express.static(path.join(__dirname, 'public')));   io.sockets.on('connection', function (socket) {     console.log('client connect');     socket.on('echo', function (data) {     io.sockets.emit('message', data);  }); });  require('./routes/api')(app,io);    console.log("Server listening at port 3000"); 

api.js:

module.exports = function(app,io) { app.put('/foo', function(req, res) {       /*          do stuff to update the foo resource          ...        */         // now broadcast the updated foo..          console.log("PUT OK!");       io.sockets.emit('update'); // how?     res.json({result: "update sent over IO"});   }); } 
like image 26
cdagli Avatar answered Oct 16 '22 06:10

cdagli


Supposing you want to access the SocketIO from anywhere in your application, not just in the router, you could create a singleton for it. This is what works for me:

//socket-singletion.js

var socket = require('socket.io');

var SocketSingleton = (function() {
  this.io = null;
  this.configure = function(server) {
    this.io = socket(server);
  }

  return this;
})();

module.exports = SocketSingleton;

Then, you need to configure it using your server:

//server config file

var SocketSingleton = require('./socket-singleton');
var http = require('http');
var server = http.createServer(app);
SocketSingleton.configure(server); // <--here
server.listen('3000');

Finally, use it wherever you want:

//router/index.js

var express = require('express');
var router = express.Router();
var SocketSingleton = require('../socket-singleton');

/* GET home page. */
router.get('/', function(req, res, next) {
  setTimeout(function(){
    SocketSingleton.io.emit('news', {msg: 'success!'});
  }, 3000);
  res.render('index', { title: 'Express' });
});

module.exports = router;
like image 24
Edudjr Avatar answered Oct 16 '22 04:10

Edudjr


One more option is to use req.app.

app.js

const express = require('express');
const path = require('path');
const logger = require('morgan');
const api = require('./routes/api');

const app = express();
const io = require('socket.io').listen(app.listen(3000));

// Keep the io instance
app.io = io;

app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));

// ...

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

module.exports = app;

routes/api.js

const express = require('express');
const router = express.Router();

router.put('/foo', function(req, res) {
    /*
     * API
     */

    // Broadcast the updated foo..
    req.app.io.sockets.emit('update', foo);
});

module.exports = router;
like image 45
Ninh Pham Avatar answered Oct 16 '22 06:10

Ninh Pham