Sockpress: wrap express and socket.io together!

Oct 21, 2014   #Project  #Node.js 

This article deals with Express.js and Socket.io integration in Node.js. These two modules are mainly used by the JavaScript community. They allow one to create powerful and stable http(s) and websockets servers in Node.js applications. NPM is the free open-source repository for node.js modules.

Introduction

A JavaScript web developper just have to use Express.js to create simple websites powered by Node.js. This simple framework manages many things for us: routes, assets, sessions, parameters … However, Express.js does not support HTML5 websockets. That’s why socket.io is often used with express. And with these two modules, here we are with a responsive and robust HTML5 server. Nice!

Here is the code for a basic Express + Socket.io server:

var app = require('express').createServer();
var io = require('socket.io')(app);

app.listen(80); // Both http and websockets servers on port 80

app.get('/', function (req, res) {
    res.sendfile(__dirname + '/index.html');
});

io.on('connection', function (socket) {
    socket.emit('news', { hello: 'world' });
});

Seems good, isn’t it? The port is shared between app and io objects. But what if we want to “link” http and sockets requests? For example:

var app = require('express').createServer();
var io = require('socket.io')(app);

app.listen(80); // Both http and websockets servers on port 80

app.get('/', function (req, res) {
    res.sendfile(__dirname + '/index.html');
});

app.post('/login', function(req, res) {
    res.send({authenticated: true});
});

io.on('connection', function (socket) {
    // how to know if the incoming socket is authenticated?
});

It is just the major issue by using Express.js and socket.io together: they don’t share a secure session object. We can use temporary tokens to check the authentification, but it would be redundant and painful. Fortunately, some npm modules are here to help us!

A first wrapper: Express.io

Managed by Techpines on github and written in CoffeeScript, Express.io is a realtime-web micro framework. It is able to resolve main Express+Socket.io issues (routing & sessions).

express = require('express.io');
app = express().http().io();

// Setup classic Express session (Express 3)
app.use(express.cookieParser());
app.use(express.session({secret: 'monkey'}));

// HTTP Routes
app.get('/', function (req, res) {
    res.sendfile(__dirname + '/index.html');
});

app.post('/login', function(req, res) {
    req.session.authenticated = true;
    res.send({authenticated: true});
});

// Realtime Routes
app.io.route('ready', function(req) {
    if(req.session.authenticated) {
        //do stuff with authenticated user!
    }
});

app.listen(80);

You can see that the req.session object is correctly shared between HTTP and realtime route. Also, you can see the app.io object: actually, socket.io’s engine is placed inside the express object. We just have to manipulate one global framework :)

But there are new issues.

  • Express.io overrides and renames Socket.io’s default functions. It’s really annoying because the socket.io doc does not fit with express.io one. A classic example with rooms: to('name') becomes room('name').
  • It is written in CoffeeScript: this language is not easy to read for beginners.
  • It is stuck with Express 3 and Socket.io 0.9, since it’s not actively maintained.
  • Socket.io 1.0 is totally different and will not work with Express.io

In front of that, I decided to write my own wrapper.

Sockpress: a KiSS Express.io alternative

(KiSS = Keep it Short and Simple)

I decided to keep it the shortest and simplest possible, because it just have to be a wrapper, not a full framework. Sail.js, another popular node.js framework, already uses Express and Socket.io internally (with plenty of other features).

That’s why Sockpress is a very short module (two files only) but well tested with unit tests. Obviously, the module is juste written in pure JavaScript. That’s how one use Sockpress:

var options = {
    secret: "a secret key for session",
}
var app = require("sockpress").init(options);

// HTTP Routes
app.get('/', function (req, res) {
    res.sendfile(__dirname + '/index.html');
});

app.post('/login', function(req, res) {
    req.session.authenticated = true;
    res.send({authenticated: true});
});

// Realtime Routes
app.io.on('connection', function(socket) {
    if(socket.session.authenticated) {
        // do stuff
    }
 }
});

From now, req and socket objects share the same session container. Please note that Sockpress does not change either Express nor Socket.io behavior. However, it adds some useful features, like IO routing:


// this route sends a message to other connected sockets

app.io.route("send message", function(socket, data) {
    socket.emit("message sent", data);
    socket.broadcast.emit("new message", data);
});

Conclusion

Keep Your Soul Project is powered by Sockpress. It’s a fine solution for projects who need both classic HTTP and websockets communications between clients and server. Sockpress seems ready for production, but I need more feedbacks to push it to 0.1.0 version!

Well, do not hesitate to test Sockpress if you need it, and send issues to the GitHub project :)