Sending real-time notifications with Socket.io in Node.js

Sending real-time notifications with Socket.io in Node.js

Websockets are a great way to create open communication between the client and the server.Great examples are Chat, Bidding System, Notifications, etc

How do websites work?

  • A user provides a URL to the web browser.
  • The browser sends a request to the web server, asking for resources related to the URL.
  • The server receives the request and sends an HTTP response containing the related files to the web browser.
  • The browser displays the response as web pages to the user.

This type of communication is an HTTP connection, suitable for applications where data doesn't change frequently.

Have you ever used a forex trading app or visited a sports betting website? You will notice that the data changes almost every minute; these changes are possible with the help of WebSockets.

WebSockets create a connection between a client and a server, allowing them to send data both ways; client-server and server-client. Compared to HTTP, WebSockets provide a lasting bi-directional client-server connection, making it possible for data to change in real-time without refreshing the page.

Novu

If you are looking to implement in-app notifications (kind of like Facebook / Instagram / Upwork etc..), Check out Novu, we bring you the whole solution without dealing with websockets / scaling / databases / servers. Come and star us ⭐️🤩 github.com/novuhq/novu

Image description

And we are back!

Node.js has a built-in WebSocket module, but this module doesn't provide the functionalities required to build complex real-time applications; this is why Socket.io exists.

Socket.io is a popular JavaScript library that allows us to create real-time, bi-directional communication between clients and a Node.js server. It is a highly performant and reliable library optimized to process a large volume of data messages with minimal delay. It follows the WebSocket protocol and provides better functionalities, such as fallback to HTTP long-polling or automatic reconnection, which enables us to build efficient chat and real-time web applications.

In this article, you'll learn how to send notifications between web clients and a Node.js server using Socket.io. Before we start coding this project, let's see how Socket.io works.

This tutorial assumes that you have a basic knowledge of building web applications with Express.js and Node.js.

How does the Socket.io library work?

Real-time Node.js applications such as forex trading, sports betting websites, chat applications, and many others use Socket.io. In this section, you'll learn how Socket.io transfer messages between the client and the server in a web application.

The Socket.io library has two parts - the client and the server API. The client API enables users to connect to the server via WebSocket, and the server API initiates a Socket.io connection on the backend server.

To connect Socket.io to the web client, you'll need to download the client JavaScript bundle via CDN or NPM.

For HTML clients, add this code within the head tag.

<script src="https://cdn.socket.io/4.5.0/socket.io.min.js" integrity="sha384-7EyYLQZgWBi67fBtVxw60/OWl1kjsfrPFcaU0pp0nAh+i8FD068QogUvg85Ewy1k" crossorigin="anonymous"></script>

The code snippet above downloads Socket.io via CDN and exposes a client bundle at /socket.io/socket.io.js to the client. We can then access Socket.io by adding the code below to the bottom of our HTML body tag.

<script src="/socket.io/socket.io.js"></script>
<script>
    const socket = io();
</script>

For React.js, Next.js, and other JavaScript libraries or frameworks, you can download the Socket.io client API via NPM.

npm install socket. io-client

For the backend server installation, you need to have at least Node.js v10 installed on your computer before you can install the Server API via NPM.

npm install socket.io

With this library, you can create a Socket.io connection, connect web clients to the backend server, and start sending messages between the client and the server. However, this is just a simple explanation of how Socket.io works. In this article, I will walk you through adding the Socket.io library to the client and the server by building a notification system.

Setting up Express.js on a Node.js server

Here, I will guide you through setting up Express.js on a Node.js server. Express.js is a fast, minimalist framework that provides several features for building Node.js web applications. It enables us to create the web client for Node.js applications.

Create a folder that will contain our app. Then, create a package.json file by running the code below.

mkdir <folder-name>
cd <folder-name>
npm init -y

Create an index.js file - the entry point to the web application.

touch index.js

Install Express.js, Nodemon, and Socket.io. Nodemon is a Node.js tool that automatically restarts the server after detecting file changes.

npm install express nodemon socket.io

Configure Nodemon by adding the start command to the list of the scripts in the package.json file. The code snippet below starts the server using Nodemon.

{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon index.js" //npm start - starts the server with Nodemon
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.1",
    "nodemon": "^2.0.19",
    "socket.io": "^4.5.1"
  }
}

Update the index.js file to render an HTML page. Copy the code below into the index.js file.

const express = require('express');
const app = express();
const path = require('path');
const PORT = process.env.PORT || 8080;

//enables us to host static CSS & JS files.
//The public folder contains the CSS & JS files.
app.use(express.static('public'));

//Route to the homepage of the application
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '/index.html'));
});

//Listens for changes in the web application
app.listen(PORT, () => {
  console.log(`App listening at ${PORT}`);
});

Create an index.html file that displays a message bar and button.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Socket IO Chat App</title>

    <!-- Link to CSS file-->
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div id="message-bar">
      <p id="notification"></p>
    </div>
    <form class="container">
      <h2>Send Messages with Socket.io</h2>
      <textarea
        rows="5"
        width="100%"
        name="message"
        id="message"
        placeholder="Enter your message..."
      ></textarea>
      <button>SEND MESSAGE</button>
    </form>
  </body>
</html>

Create a folder named public. This folder will contain the CSS file for the HTML page.

mkdir public
cd public
touch index.css

Copy the code below into the index.css file

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-family: 'Poppins', sans-serif;
}
#message-bar {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
#notification {
  color: #fff;
}
.container {
  height: 80vh;
  width: 100%;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
h2 {
  text-align: center;
  margin-bottom: 30px;
}
textarea {
  font-size: 16px;
  margin-bottom: 30px;
  padding: 15px;
  outline: none;
}
button {
  width: 200px;
  padding: 15px;
  cursor: pointer;
  background-color: #2c3639;
  outline: none;
  border: none;
  color: #dcd7c9;
  font-size: 16px;
}
button:hover {
  background-color: #3f4e4f;
}

Run the Node.js server. You can view the index.html file at https://localhost:8080 in your web browser.

npm start

Configuring Socket.io on the client

In this section, I will walk you through connecting the web client to Socket.io.

Update the index.html file to connect Socket.io JavaScript bundles via CDN. Add the first snippet within the head tag and the other at the bottom of the body tag.

<head>
    <!-- This links to Socket.io client JavaScript bundle via CDN. -->
    <script
      src="https://cdn.socket.io/4.5.0/socket.io.min.js"
      integrity="sha384-7EyYLQZgWBi67fBtVxw60/OWl1kjsfrPFcaU0pp0nAh+i8FD068QogUvg85Ewy1k"
      crossorigin="anonymous"
    ></script>
  </head>
<body>
......
The page content
.....
    <!-- Link to the JavaScript file-->
    <script src="./script.js" type="module"></script>

    <!-- This access the client JavaScript bundle provided via its CDN -->
    <script src="/socket.io/socket.io.js"></script>
  </body>

Create a JavaScript file - script.js that enables us to access the user's inputs and the HTML elements on the webpage via JavaScript DOM.

cd public
touch script.js

Access the HTML elements via the Document Object Model provided by JavaScript.

//In script.js

const notify = document.querySelector('#notification');
const message = document.querySelector('#message');
const button = document.querySelector('button');
const messageBar = document.querySelector('#message-bar');

Create an event listener that logs the message provided by the user to the console whenever the form is submitted.

function printMessage(e) {
  e.preventDefault();
  console.log(message.value);
}
button.addEventListener('click', printMessage);

Next, add Socket.io to the client JavaScript file - script.js.

const socket = io();

socket.on('response', (data) => {
  notify.textContent = data;
  messageBar.style.backgroundColor = '#3F4E4F';
  messageBar.style.height = '20vh';
});

The code snippet above listens for messages labeled response from the server. If there is a message, it displays the message on the webpage.

Edit the printMessage function to send messages from the client to the Node.js server. The code snippet below sends messages to the server when a user clicks the submit button.

function printMessage(e) {
  e.preventDefault();
  socket.emit('message', message.value);
}

Adding Socket.io to the Node.js server

In this section, you will learn how to configure Socket.io on a Node.js server, and you can receive and send messages from the client via Socket.io.

Update the index.js by importing Socket.io and the HTTP module from Node.js. The HTTP module creates an HTTP server that allows Node.js to transfer data via the network.

const express = require('express');
const app = express();
const path = require('path');
const PORT = process.env.PORT || 8080;

//New imports
const http = require('http').Server(app);
//Pass the Express app into the HTTP module.
const socketIO = require('socket.io')(http);

app.use(express.static('public'));

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '/index.html'));
});

//Listen for changes on the HTTP server not the Express server
http.listen(PORT, () => {
  console.log(`App listening at ${PORT}`);
});

From the code snippet above, the HTTP server accepts the Express app as a parameter, and we listen for changes on the HTTP server instead of Express.

Before the app.get() block, create a connection to the web client with Socket.io.

socketIO.on('connection', (socket) => {
  console.log(`⚡: ${socket.id} user just connected`);
  socket.on('disconnect', () => {
    console.log('A user disconnected');
  });
});

The socket.io("connection") function above creates a connection with the web client. Socket.io creates a unique ID for each client and logs the ID to the console whenever a user visits the web page. When you refresh or close the web page, the socket fires the disconnect event showing that a user has disconnected from the socket.

Next, update the function to send and receive data from the client.

socketIO.on('connection', (socket) => {
  console.log(`⚡: ${socket.id} user just connected`);
  socket.on('disconnect', () => {
    console.log('A user disconnected');
  });

  socket.on('message', (data) => {
        //sends the data to everyone except you.
    socket.broadcast.emit('response', data); 

        //sends the data to everyone connected to the server
    // socket.emit("response", data)
  });
});

*socket.broadcast.emit() - sends the data to everyone except you, and the socket.emit() - sends the data to everyone connected to the server, including you*

Congratulations!🎊 You've just completed the project for this tutorial.

Conclusion

In this tutorial, you've learned

  • What WebSockets are
  • Why and when do we need Socket.io?
  • How to connect Socket.io to a web client and a Node.js server, and
  • how to send messages between an HTML client and a Node.js server.

Socket.io supports private messaging and group chats, identifying users by nicknames, showing whether a user is online, and knowing if a user is typing.

With these features provided by Socket.io, you can build complex real-time applications useful in various industries such as aviation, gaming, media, and finance.

Socket.io is an excellent choice for real-time communication between a client and a Node.js server. Some other libraries like Twilio, Firebase, Supabase, and many others support real-time communication. Feel free to check them out.

Thank you for reading, You can find the full source-code here: github.com/novuhq/blog/tree/main/sending%20..