Realtime Web-based Chat in Node JS & MySQL

Node JS is a web server that runs under the most famous and widely used programming language, Javascript. As Javascript is asynchronous, so Node JS server can fulfil client requests without having to wait for previous instruction to execute. Node JS runs in non-blocking event, which means that if there is any statement that takes too much time then Node JS will not get stuck at that point rather it will move to the next statement. Node JS can generate dynamic content of a website so user does not have to refresh the page in order to see updated data. This is very useful in realtime applications such as chat apps and google maps etc.

Node JS server runs on a single executable file, that file can include other multiple files too. But the server will be executing just the main file. Typically, that file named as “server.js” or “main.js” and that depends if you wanted to have different servers in same folder. That file will be executed just once and then will keep listening to incoming events, as soon it receives a new event it will send it back to other clients. Every time you run the Node JS file, all previous variables, arrays, objects will be destroyed. That is why it is recommended to store that data in some database.

When it comes to the database Node JS has multiple options. You can use MySQL which is famous relational database structure and it is widely used in web development all over the world. Tech giants like Facebook uses MySQL as backend database. Or you can use Mongo DB which is a relation-less data structure, here data is stored in collections and documents. Collection will be name of entity and document is a single record exist in some collection. For example, you will have a collection of user and whenever a new user registered, a new document will be created inside this collection. It is must faster than MySQL. Or you can use a file system where everything will be saved in file, it is the least recommended method but you can use this for exporting data in external formats. You can have .CSV format which is Comma Separated Values and this type of file usually gets opened in Microsoft Excel (Windows) or Numbers (Macintosh). Similarly, you can use JSON format to store data in files and this type of files holds data in forms of arrays and objects, they are typically used for statistics, for example:

{
    users: [
        { january: 123 },
        { february: 100 },
        { march: 114 },
        { april: 138 }
    ]
}

Installation and setup

First you need to download and install Node JS server in your system. You can download it from it’s official site. After installation, you need to create a folder anywhere in your system and create a file named “server.js”. Make sure the extension of file must be “.js” because the code will be in Javascript. Write the following simple line inside this file, it will show “Hello world !” when the server runs:

server.js

console.log("Hello world !");

Open terminal (CMD) and change the directory to your project folder (cd /path/to/project/). Run the following command in the terminal:

> npm init
> npm install -g nodemon

The first command will start your project folder as Node JS project and it will ask several questions like author (your) name, version etc. Just keep hitting enter if you wanted to skip these. Second command will install nodemon module globally in your system. This is helpful because nodemon allows you to make changes in server file without having to worry to restart the server. Whenever you made any changes in server file, nodemon will automatically restart the server. Otherwise, you have to restart it manually every time you make any change in server file. Now go ahead and run the following command in your terminal, make sure your project’s directory is opened in terminal:

nodemon server.js

When you run the above command, you will see a message saying “Hello world !”. Now install the Express and Http modules in your project by running the following commands, you may need to stop the nodemon running command by hitting Ctrl + C:

> npm install express
> npm install http

After installation you need to create an instance of these modules in your “server.js” file:

// use express
var express = require("express");

// create instance of express
var app = express();

// use http with instance of express
var http = require("http").createServer(app);

To start the server, call the listen function from http object and pass the port number as a parameter. Second parameter is a function that will be called when the server starts running:

// start the server
var port = 3000;
http.listen(port, function () {
    console.log("Listening to port " + port);
});

After pasting these lines in “server.js” you need to run “nodemon server.js” again in the terminal so that the server will keep running on this port.

Socket for incoming connections

Install socket module in your project by running the following command:

> npm install socket.io

And in your “server.js” create an instance of it:

// create socket instance with http
var io = require("socket.io")(http);

To receive incoming connections, you need to attach “connection” event listener on IO object:

// add listener for new connection
io.on("connection", function (socket) {
	// this is socket for each user
	console.log("User connected", socket.id);
});

Whenever a new user connects, this function will be called and we will get it’s socket object in the function argument. We can use the socket ID to send event to specific users. Following is a list of useful functions that you can perform using these IO and socket objects:

EventPurpose
socket.to(socket.id).emit(“name”, “value”)Sends the value to specific user.
io.emit(“name”, “value”)Sends the value to all connected users.
socket.emit(“name”, “value”)Sends the value back to the user who called this event.
socket.broadcast.emit(“name”, “value”)Sends the value to all users except the one who called this event.

Sending message event

Download and save the socket.io.js file in your project, create a folder named “js” where all JS files will be saved. You can download socket IO from here. Create a file named “index.html” at the root of your project’s folder and include this socket file as Javascript.

<script src="js/socket.io.js"></script>

Then you need to create an instance of socket IO with the same port number as specified in “server.js”. Paste the following code in “index.html”:

<script>
    var server = "http://localhost:3000";
    var io = io(server);
</script>

When you run the index.html in your browser, you will see in your terminal a message for new user connection with a unique socket ID. Paste the following line in your “index.html” inside script tag, it will send the event to server:

// sending message from client
io.emit("new_message", "New message");

And paste the following line in “server.js”, it will receive the event sent from server. This line must be inside IO connection event:

// server should listen from each client via it's socket
socket.on("new_message", function (data) {
	console.log("Client says", data);
});

Run the “nodemon server.js” command again to start the server and refresh the index.html page in your browser and you will see “Client says New message” in your terminal. So now you can create a form where user will enter his desired message and upon hitting submit button, that event will be fired to server. Paste the following code in “index.html” file:

<form onsubmit="return sendMessage();">
	<input id="message" placeholder="Enter message">
	<input type="submit" value="Send">
</form>

<script>
function sendMessage() {
	// get message
	var message = document.getElementById("message");

	// sending message from client
	io.emit("new_message", message.value);

	// this will prevent the form from submitting
	return false;
}
</script>

Now if you refresh the index.html file, you will see a form with an input field to enter message and a button. Write any message you want and click send button and you will see that message in your terminal window. Now server needs to respond back to all users that a new message has been received. First send the message from server to all connected clients:

// change in server.js inside IO "connection" event
// server should listen from each client via it's socket
socket.on("new_message", function (data) {
	// server will send message to all connected clients
	// send same message back to all users
	io.emit("new_message", data);
});

It will send the same message back to all connected clients. Now all clients must be listening from server for that event, once that event is triggered from server then all clients will show the new message. Paste the following code in “index.html” inside script tag:

// client will listen from server
io.on("new_message", function (data) {
	console.log("Server says", data);
});

Now refresh the page and open a new browser window or you can use different browsers if you have multiple browsers installed in your computer. Then open both browsers side by side. Send message from 1 browser and you will see the message in console of other browser. You can open console by right clicking in empty area and selecting “Inspect Element” option. Create a <ul> tag to display all incoming messages in a list in “index.html”:

<!--list where all messages will be displayed-->
<ul id="messages"></ul>

And paste the following code in “new_message” event in “index.html” file:

// client will listen from server
io.on("new_message", function (data) {

    // display message
    console.log("Server says", data);
    
    // creates a new DOM element for li tag
    var li = document.createElement("li");

    // show message in li item
    li.innerHTML = data;

    // append the message at the end of list
    var messages = document.getElementById("messages");
    messages.appendChild(li);
});

Refreshing the page and you will be able to send message from a form and it will be display on the other browser in a list. Send multiple messages and all will be displayed at the end of list. When you refresh the page you will see an empty page because the server only listens to incoming messages. In order to see old messages you can either create an array or store all messages in database. Creating an array will remove all messages when the server restarted. So we are going to save in database.

Connect Node JS with MySQL

First you need to install a module named mysql, stop the server and run the following command in your terminal. You can stop the server by pressing Ctrl + C.

npm install mysql

Make sure to run “nodemon server.js” again to start the server.

Create a database in your phpMyAdmin named “web_chat” and inside this database create a table named “messages”. This table can have only 2 fields just for the sake of simplicity, auto increment integer “id” and TEXT “message”. ID will be used when deleting the message. Your table structure should be . Create mysql module instance in “server.js” file and start a new connection with database:

// use mysql
var mysql = require("mysql");

// create connection
var connection = mysql.createConnection({
	host: "localhost",
	user: "root",
	password: "",
	database: "web_chat"
});

connection.connect(function (error) {
	// show error, if any
});

Save messages in MySQL

In “server.js” change the “new_message” event to save the incoming message in database before notifying to all other clients:

// server should listen from each client via it's socket
socket.on("new_message", function (data) {
	console.log("Client says", data);

	// save message in database
	connection.query("INSERT INTO messages (message) VALUES ('" + data + "')", function (error, result) {
		// server will send message to all connected clients
		io.emit("new_message", {
			id: result.insertId,
			message: data
		});
	});
});

This will save the incoming message in database and return the new row inserted ID which can be used to delete the message. Similarly, change your “new_message” event in “index.html” to display the message as:

li.innerHTML = data.message;

If you try to send a message now, you will see that message will also get saved in database table. Now you need to display all previous messages to a client when connected.

Reading messages from MySQL

Download and save the jquery.js file in your project’s js folder. You can download jQuery from it’s official site and include it in your “index.html” file.

<script src="js/jquery.js"></script>

Paste the following code anywhere in the script tag in “index.html”. It sends an API request to Node JS server and display all messages returned from server. Since the data returned from server will be in JSON string, so we have to convert it back to Javascript object by parsing.

$.ajax({
	url: server + "/get_messages",
	method: "GET",
	success: function (response) {
		console.log(response);

		var messages = document.getElementById("messages");

		// parse JSON to javascript object
		var data = JSON.parse(response);
		for (var a = 0; a < data.length; a++) {
			// creates new DOM element
			var li = document.createElement("li");

			// add message content as HTML
			li.innerHTML = data[a].message;

			// append at the end of list
			messages.appendChild(li);
		}
	}
});

Now in “server.js” you need to set header to allow API requests from unknown sources. Since you are testing it from localhost and that is not known for Node JS so you can add a header for “Access-Control-Allow-Origin” and allow all origins by setting it’s value to “*”. Paste the following code outside of IO “connection” event:

// add headers
app.use(function (request, result, next) {
	result.setHeader("Access-Control-Allow-Origin", "*");
	next();
});

next() is a callback function that will attach these headers with incoming API requests. And you need to create an API for “get_messages” that will return all the saved messages in database. Paste the following code in “server.js” outside of IO “connection” event:

// create API for get_message
app.get("/get_messages", function (request, result) {
	connection.query("SELECT * FROM messages", function (error, messages) {
		// return data will be in JSON format
		result.end(JSON.stringify(messages));
	});
});

Since “result.end” can only send string data in response, so you can convert your objects into JSON string and can parse this JSON string back to Javascript objects at client side. Refresh the page and now you will see all previous messages sent in this chat. If you send or receive a new message it will be appended at the end of same list and upon refreshing it will not be removed, because it will already get saved in database.

Delete message

If you have used WhatsApp then you probably know about the delete message feature. Your friend sends you a message and you saw it, then he deletes it and suddenly a message appeared to you “This message has been deleted”. This can be done via Node JS where deleting message from sender will make that message removed from all other users all of a sudden. First you need to create a delete button in 2 functions, when all messages are fetched from database and when a new message has been received. Change the for loop inside “get_messages” AJAX call in “index.html” file:

// give it unique id
li.id = "message-" + data[a].id;

li.innerHTML = data[a].message;

// add delete button
li.innerHTML += "<button data-id='" + data[a].id + "' onclick='deleteMessage(this);'>Delete</button>";

Above code should be pasted inside for loop before appending the child. In your “new_message” event in “index.html”, paste the following code before appending the child:

// same here
li.id = "message-" + data.id;

li.innerHTML = data.message;

// display delete button here too
li.innerHTML += "<button data-id='" + data.id + "' onclick='deleteMessage(this);'>Delete</button>";

Now inside your <script> tag create a new function that will get the message ID and send the delete event to the server with selected message ID:

function deleteMessage(self) {
	// get message id
	var id = self.getAttribute("data-id");

	// send event to server
	io.emit("delete_message", id);
}

In your “server.js” that event will be listened and delete the message from database. After deleting, an event will be sent to all users to remove that message from list. Paste the following code in your IO “connection” event:

// attach listener to server
socket.on("delete_message", function (messageId) {
	// delete from database
	connection.query("DELETE FROM messages WHERE id = '" + messageId + "'", function (error, result) {
		// send event to all users
		io.emit("delete_message", messageId);
	});
});

Now all clients must be listening continuously for delete event and you can remove that list item as soon as user receives that event. We are making it to show “This message has been deleted” similar to WhatsApp when delete event is received from server. So paste the following code in your “index.html” script tag:

// attach listener on client
io.on("delete_message", function (id) {
	// get node by id
	var node = document.getElementById("message-" + id);
	node.innerHTML = "This message has been deleted";
});

Refresh both browsers and try to send message from one browser to anther. You will see a delete button along with message text. When you click that button from one browser, that message will gets deleted from both browsers and instead you will see a message “This message has been deleted”.

Display name with message

At this point, when you send or receive a message you only see the content of message but you also wanted to know WHO sends that message. So first create a form where user can enter his name and then that name will be sent along with his message. In your “index.html” file before send message form, create a simple form like below:

<form method="POST" onsubmit="return setUsername();">
	<input type="text" autocomplete="off" id="username" placeholder="Enter username">
	<input type="submit" value="Select">
</form>

In the same file inside the <script> tag create a function that will create a global variable named “username”:

var username = "";

function setUsername() {
    username = $("#username").val();
	
    // this will prevent the form from submitting	
    return false;
}

Now change the “sendMessage” function to the following so that it will send the username along with message to the server:

function sendMessage() {
	// get message
	var message = document.getElementById("message");

	// sending message from client
    io.emit("new_message", {
        message: message.value,
        username: username
    });

	// this will prevent the form from submitting
	return false;
}

Now in “new_message” event in same file, change the line which append the message content in <li> tag to the following:

li.innerHTML = "" + data.username + ": " + data.message;

Same goes in “get_messages” AJAX call in “index.html”, change the line which append the message content in <li> tag to the following:

li.innerHTML = "" + data[a].username + ": " + data[a].message;

The above line will display the name of user in bold and message in normal style. You can save the username in messages table in database too by first creating a column named “username” and it’s value must be TEXT. Then in “server.js” inside IO “connection” event change the socket’s “new_message” to the following:

// server should listen from each client via it's socket
socket.on("new_message", function (data) {

    // save message in database
	connection.query("INSERT INTO messages(username, message) VALUES('" + data.username + "', '" + data.message + "')", function (error, result) {
		data.id = result.insertId;
		io.emit("new_message", data);
	});
});

Conclusion

Node JS plays a very important role in web development especially in realtime environment. Apart from just creating a chat app, you can create a notification system where someone’s activity is monitored realtime by others, or maps that share realtime live location between friends etc. If you wanted to have the chat app with the design as above, you can download all source files from the button below. Make sure you download them and let us know if you face any issue.

4 Replies to “Realtime Web-based Chat in Node JS & MySQL”

Leave a Reply

Please disable your adblocker or whitelist this site!