joseverissimo
Published 8 Oct, 2018

Real-time chat application using Express and Socket.io

We are going to be using the library Socket.io because it supports the use of WebSockets.

Also if for some reason the user is on an older browser or on a proxy connection that does not support WebSockets, socket.io will fall back to Long Polling which is an alternative method that we could have used to create this application.

1. Installing

To start off, create a folder in a preferred location, then open a terminal window and change the working directory to the folder you have just created.

Bash
# Create a directory
mkdir ./real-time-chat
cd real-time-chat

Now, download and install the dependencies that we need. We will use the Node Package Manager to do so.

~/real-time-chatBash
# Initialise NPM
npm init --yes

# Install the server-side technologies
npm install express socket.io --save

Once these dependencies have finished downloading, we can go ahead and install the client-side libraries.

But first, create a file in the following path: app/views/index.html - this will include the form that we will use to retrieve and send messages on our chat application. In this file add the following HTML:

app/views/index.htmlHTML
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Real time chat</title>
    </head>
    <body>

        <h2>Welcome to the chat forum</h2>

        <!-- Chat form. -->
        <form name="chat-form">
            <div class="form-group">
                <label for="username-input">Username</label>
                <input type="text" class="form-control" id="username-input" name="username-input">
            </div>
            <div class="form-group">
                <label for="message-input">Your Message</label>
                <textarea name="message-input" class="form-control" id="message-input" cols="12" rows="2" required></textarea>
            </div>
            <button type="submit" class="btn btn-primary">Send Message</button>
        </form>

        <!-- Chat history. -->
        <h3>Chat</h3>
        <div id="chat-content" class="card">
            <div class="card-body">
            </div>
        </div>


        <!-- Client-side Socket.io -->
        <script src="/js/socket.io.js"></script>

        <!-- Custom JavaScript -->
        <script src="/js/scripts.js"></script>
        
    </body>
</html>

In this specific tutorial I will not be adding the styles, but feel free to add any styles or even modify the structure of the HTML.

2. Set up the Express server

To set up the Express server we will first need to create the main file app/app.js. In this file, we will need to require the Express dependency and start a server on the port 3000.

Also, set the views folder to app/views, since we've created the HTML file that contains the form in there.

app/app.jsJavaScript
var express = require("express"); // Require the Express library.
var app = express(); // Create app instance.

app.set('port', process.env.PORT || 3000); // Port for server.
app.set('views', 'app/views'); // Set views.

Now, we can specify the folder that will contain the static files for the application, this will allow us to serve the script.js and socket.io.js files that we have specified earlier in the HTML file.

In regards to the socket.io.js file, you can download it on the Socket.io's website.

app/app.jsJavaScript
// Access to public files.
app.use(express.static('app/public'));

Serving static files is now possible, although, we still need to be able to serve an actual page with content. And in this case, we want to serve the chat HTML page we created earlier, whenever the user goes to our website's homepage.

After this, we can start the server, by listening to connections on the port specified earlier.

app/app.jsJavaScript
// Respond with our HTML page when a GET request is made on the homepage.
app.get('/', function(req, res) {
    res.render('index');
});

// Listen for connections on the port 3000.
var server = app.listen(app.get('port'), function() {
    console.log('Listening on port ' + app.get('port'));
});

You should now be able to run the code above and have a perfectly running server, to do this open your terminal and execute node app/app.

3. Integrate the Socket.io logic with Express

The integration of Socket.io with Express is fairly easy. So, we would first need to require the socket.io library in the app/app.js file and specify the server that's listening for connections.

app/app.jsJavaScript
// Get the socket.io application.
var io = require('socket.io')(server);

Socket.io allows you to send and receive events but before we can do this, we would first have to listen for a connection event, like the name suggests this listener event is fired whenever a new connection is established. This specific listener event has a callback that provides us with a socket variable, which handles the connection for a namespace.

Use the socket variable to listen for the user-defined event messageSent.

Whenever the messageSent event is triggered, let's emit an event back to everyone in the namespace, including the sender, this will have the data that was sent to the server.

app/app.jsJavaScript
// Listen for connections.
io.on('connection', function(socket) {
    socket.on('messageSent', function(data) {
       io.emit('messageUpdate', data);
    });
});

And this should be all we need to do to integrate Socket.io with Express.

4. Set up the client-side logic

All that is left to do, is to create the client-side logic that will send and receive events to the Express server.

Start by creating the javascript file that we are including in the HTML file earlier on, so app/public/js/scripts.js.

Now, let's connect to our express server and then listen for a connection event, this function will be called whenever the user connects.

app/public/js/scripts.jsJavaScript
// Connect to server
var socket = io.connect('http://127.0.0.1:3000');

// Listen for connection event
socket.on('connect', function(data) {
    // ...
});

Once the user has connected, we can then get the form element that we specified in the HTML and also get the username and message inputs so that we can use their values to send to the server as a message event.

app/public/js/scripts.jsJavaScript
// ...
// Get the form element
var chatForm = document.forms['chat-form'];

if (chatForm) {
    // Get the element inputs
    var username = document.querySelector('#username-input');
    var message = document.querySelector('#message-input');
}

Now that we have the form element, add an event listener, that is triggered whenever the form is submitted.

When the form submitted by the user, get the username and message values and store these in an object called data.

Emit this object as an event called messageSent, which our server is listening for.

If you recall, the server is waiting for this event and then straight away it sends a messageUpdate event back, to let everyone in the namespace know about this new message.

Lastly, simply clear the message input and focus on it.

app/public/js/scripts.jsJavaScript
// ...
// On form submit show the message and emit an event to the local server.
chatForm.addEventListener('submit', function(e) {

    // Prevent the form from submitting all together.
    e.preventDefault();

    var data = {
        username: username.value,
        message: message.value
    };

    // Emit event to local host.
    socket.emit('messageSent', data);

    message.value = "";
    message.focus();
});

All that is left to do, is to add a listener on messageUpdate and then show that message to the end user.

app/public/js/scripts.jsJavaScript
// ...
    // Listen for the chatMessage event.
    socket.on('messageUpdate', function(data) {
        // Show the message.
        showMessage(data);
    });

}

// Display message for user.
function showMessage(data) {
    var chatDisplay = document.querySelector('#chat-content .card-body');
    var newMessage = document.createElement('p');
    newMessage.className = 'chat-text';
    newMessage.innerHTML = '<strong>' + data.username + '</strong>: ' + data.message;

    chatDisplay.insertBefore(newMessage, chatDisplay.firstChild);
}

And this should be all you need to create a very basic chat form application!

So to be able to access this application, start the first by opening your terminal and executing node app/app and then visit the following URL http://localhost:3000.