Node.js: Initializing Socket.IO with Express

Socket.IO works by wrapping itself around an HTTP Server object. Think back to Chapter 4, HTTP Servers and Clients, where we wrote a module that hooked into HTTP Server methods so that we could spy on HTTP transactions. The HTTP Sniffer attaches a listener to every HTTP event to print out the events. But what if you used that idea to do real work? Socket.IO uses a similar concept, listening to HTTP requests and responding to specific ones by using the Socket.IO protocol to communicate with client code in the browser.

To get started, let’s first make a duplicate of the code from the previous chapter. If you created a directory named chap08 for that code, create a new directory named chap09 and copy the source tree there.

We won’t make changes to the user authentication microservice, but we will use it for user authentication, of course.

In the Notes source directory, install these new modules:

$ npm install socket.io@2.x passport.socketio@3.7.x –save

We will incorporate user authentication with the passport module, used in Chapter 8, Authenticating Users with a Microservice, into some of the real-time interactions we’ll implement.

At the beginning of app.mjs, add this to the import statements:

import socketio from ‘socket.io’;

import passportSocketIo from ‘passport.socketio’;

This code brings in the required modules. The socket.io package supplies the core event-passing service. The passport.socketio module integrates Socket.IO with PassportJS-based user authentication. We will be reorganizing app.mjs so that session management will be shared between Socket.IO, Express, and Passport.

The first change is to move the declaration of some session-related values to the top of the module, as we’ve done here:

import session from ‘express-session’;

import sessionFileStore from ‘session-file-store’;

const FileStore = sessionFileStore(session);

export const sessionCookieName = ‘notescookie.sid’;

const sessionSecret = ‘keyboard mouse’;

const sessionStore = new FileStore({ path: “sessions” }); 

What this does is create a couple of global scope variables to hold objects related to the session configuration. We had been using these values as constants when setting up the Express session support. We now need to share those values with both the Socket.IO and the Express session managers. When we initialize both Express and Socket.IO session handlers, there is an initialization object taking initialization parameters. In each, we will pass in the same values for the secret and sessionStore fields, to ensure they are in agreement.

The next change is moving some code related to setting up the server object from the bottom of app.mjs closer to the top, as shown here:

export const app = express();

export const port = normalizePort(process.env.PORT || ‘3000’);

app.set(‘port’, port);

export const server = http.createServer(app);

server.listen(port);

server.on(‘request’, (req, res) => {

debug(‘${new Date().toISOString()} request ${req.method}

${req.url}’);

});

server.on(‘error’, onError);

server.on(‘listening’, onListening);

export const io = socketio(server);

io.use(passportSocketIo.authorize({

cookieParser: cookieParser,

key: sessionCookieName,

secret: sessionSecret,

store: sessionStore

}));

In addition to moving some code from the bottom of app.mjs, we’ve added the initialization for Socket.IO. This is where the Socket.IO library wraps itself around the HTTP server object. Additionally, we’re integrating it with the Passport library so that Socket.IO knows which sessions are authenticated.

The creation of the app and server objects is the same as before. All that’s changed is the location in app.mjs where that occurred. What’s new is the io object, which is our entry point into the Socket.IO API, and it is used for all Socket.IO operations. This precise object must be made available to other modules wishing to use Socket.IO operations since this object was created by wrapping the HTTP server object. Hence, the io object is exported so that other modules can import it.

By invoking socketio(server), we have given Socket.IO access to the HTTP server. It listens for incoming requests on the URLs through which Socket.IO does its work. That’s invisible to us, and we don’t have to think about what’s happening under the covers.

The io.use function installs functions in Socket.IO that are similar to Express middleware, which the Socket.IO documentation even calls middleware. In this case, the middleware function is returned by calling passportSocketIO.authorize, and is how we integrate Passport authentication into Socket.IO.

Because we are sharing session management between Express and Socket.IO, we must make the following change:

app.use(session({

store: sessionStore,

secret: sessionSecret,

resave: true,

saveUninitialized: true,

name: sessionCookieName

}));

initPassport(app);

This is the same configuration of Express session support that we added in Chapter 8, Authenticating Users with a Microservice, but modified to use the configuration variables we set up earlier. Done this way, both Express and Socket.IO session handling is managed from the same set of information.

We have accomplished the basic setup of Socket.IO in our Express application. First, we connected the Socket.IO library to the HTTP Server so that it can handle requests on the Socket.IO service. Then we integrated it with Passport session management.

Let’s now learn how we can use Socket.IO to add real-time updating in Notes.

Source: Herron David (2020), Node.js Web Development: Server-side web development made easy with Node 14 using practical examples, Packt Publishing.

Leave a Reply

Your email address will not be published. Required fields are marked *