facebookinstagrammailtwitter

verwebbt

socket.io in an express app

Socket.io’s Documentation on how to use it with expressjs is slightly not-so-useful. Most likely you will have some MVCish pattern and your controller is far away from where your app lives. I guess you are using express.Router() (at least you should), making it even more difficult to pass the socket.io instance through some require calls. A solution to this occurred to me in the shower.

For simplifying things I wrote this in one file.

var http = require('http')
  , express = require('express')
  , socketio = require('socket.io');
var app = express()
  , sio = socketio();

/**
 * Middleware
 */
// This attaches the socket.io instance
// to the request object
app.use(function(req, res, next) {
  req.io = sio; next();
});

// More middleware, like the following
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, './public')));

/**
 * Router
 */
app.get('/', function(req, res) {
  req.io.sockets.emit('hi', { hello: 'world' });
  res.send('Hello World');
});

/**
 * Server creation
 */
var server = http.createServer(app);
server.listen(3000);
sio.listen(server);

See what we did there? The socket.io instance is attached to the request. You can access it wherever you have access to the request object, like in your controller!

In this example the „controller“ called on app.get('/', ... will emit a event into the room hi with the content { hello: 'world' }. Of course your Router should be a express.Router() required from somewhere. Since socket.io is now in the request, it will just work there, too.

If you use express-generator the file above will look a bit like your app.js just without the Server creation part. This part is in /bin/www, therefore we need to adjust a few things.

// app.js
// ...
app.get('/', function(req, res) {
  req.io.sockets.emit('hi', { hello: 'world' });
  res.send('Hello World');
});

module.exports.express = app;
module.exports.sio = sio;
// bin/www
#!/usr/bin/env node
var http = require('http')
  , app = require('../app').express
  , sio = require('../app').sio;

var server = http.createServer(app);
server.listen(3000);
sio.listen(server);

Have in mind that socket.io in your controller is just useful (but very useful) for emitting events. Listening on events should be done somewhere else, because the controller is just called on a request and exits after that. Use socket.io for listening like you would do without express, at best in a separate file. But I think you get the idea by now.

Comments

  • King Rui:

    Perfect! It works for me. Thank you very much!

    • Timo:

      Glad I could help!

  • Jonathan:

    This is such a brilliant, simple, elegant solution – and exactly what I have been struggling to implement for the last few days. I can’t wait to try it out!