Private user to user chat in Node JS & MySQL
Private chat does not mean that there is not any server between sender and receiver. There will always be a server in the middle of you and the person you are chatting with. That does not mean that they are spying on your data. It means that they are providing you a medium where you can send and receive messages from others.
It is cost effective since you do not have to pay or worry about the server. A realtime server could take a lot of physical space. It also needs to be air-cooled 24 hours a day, 7 days a week. Also, you need to maintain those servers time-to-time from any failure. You also have to consider all the possible attacks from hackers.
Node JS
Node JS is a Javascript based server that provides realtime event notifications. It is the first thing that came in the mind of developers when they have to develop a private chat. Or even group chat. When you use Facebook, you do not need to refresh the page to see new likes or comments. When you receive a new notification, it will automatically be displayed at the corner left of screen.
Here’s how it works, when you send a message an event will be sent to the server to notify that user. Server will receive that event and send the same event to that specific user. Every user will be listening from server for incoming events. Now, whenever that event received from server a notification will be displayed. You can download and install Node JS from it’s official site.
Setup the project
Create a new folder anywhere in your computer (Node JS can run in any directory). Open that folder in terminal by running command:
cd "path_to_folder"
If you have downloaded and installed Node JS in your computer, you can run the following command to initialize the project:
npm init
You will be asked a series of questions like author, name, description, version etc. You can press enter for all these fields. Then you need to install Express, Http and Socket IO modules. Run the following commands one by one:
npm install express http socket.io
npm install -g nodemon
You do not need to run the last command if you have already installed the “nodemon” module, it helps to keep the server running and the server will restart itself if any change has been made in the server file. The above commands will install the necessary modules to start the server. Next, you are going to need is to download jQuery and Socket IO JS. You can download jQuery from here and Socket IO from here.
Create a new folder named “JS” and paste these files there. Then create a file at the root of your project folder and named it “server.js”, this will be served as your server. Open that file and paste the following code into it:
server.js
// creating express instance
var express = require("express");
var app = express();
// creating http instance
var http = require("http").createServer(app);
// creating socket io instance
var io = require("socket.io")(http);
// start the server
http.listen(3000, function () {
console.log("Server started");
});
To start the server, open back the terminal and run the following command:
nodemon server.js
This will keep the server running and whenever you make any changes in “server.js” it will automatically restarts itself.
Display connected users
For private chat, the user must select the person he wants to chat with. To do that, create a new file, which will served as a client, named “index.php”. Paste the following code in it:
index.php
<!-- include jquery and socket IO -->
<script src="js/jquery.js"></script>
<script src="js/socket.io.js"></script>
<script>
// creating io instance
var io = io("http://localhost:3000");
var receiver = "";
var sender = "";
</script>
server.js
io.on("connection", function (socket) {
console.log("User connected", socket.id);
});
The client will connect with the server and the server will keep listening from the client. As soon as one client connected IO “connection” event will be fired and his socket will be created with a unique ID. Now create a form to enter username and that name will be sent along with each user’s message.
index.php
<form onsubmit="return enterName();">
<input id="name" placeholder="Enter name">
<input type="submit">
</form>
<ul id="users"></ul>
<script>
function enterName() {
// get username
var name = document.getElementById("name").value;
// send it to server
io.emit("user_connected", name);
// save my name in global variable
sender = name;
// prevent the form from submitting
return false;
}
// listen from server
io.on("user_connected", function (username) {
var html = "";
html += "<li><button onclick='onUserSelected(this.innerHTML);'>" + username + "</button></li>";
document.getElementById("users").innerHTML += html;
});
function onUserSelected(username) {
// save selected user in global variable
receiver = username;
}
</script>
server.js
var users = [];
io.on("connection", function (socket) {
console.log("User connected", socket.id);
// attach incoming listener for new user
socket.on("user_connected", function (username) {
// save in array
users[username] = socket.id;
// socket ID will be used to send message to individual person
// notify all connected clients
io.emit("user_connected", username);
});
});
Now a form will be displayed where you can enter your name. When form submits, a function named “enterName()” will be called which stored your entered name in a global variable and send an event to the server with that name. The server will listen that event from the client, a new array will be created which holds socket ID of each user identified by his username and send the same event to all connected clients.
Same event is also attached on client side which when called will create a button with username and append it into a list. When that button is pressed, then a function will be called which stores that person’s name in another global variable. These global variables will be used when sending the message.
Send private chat message to selected user
Select a person from the list and now if you open your browser console, you will be able to enter variable “receiver” and it will print out the selected username. Similarly, you can enter “sender” and it will print your name. To send a message you have to follow almost same steps as for displaying connected users.
Create a form, on submit send an event to server. Server will get that person’s socket ID from his username and send an event to that person only. Every user will be listening for that event, whenever that event is received, display the incoming message in a list. After sending message you have to append in the list too so you can see your own messages too.
index.php
<form onsubmit="return sendMessage();">
<input id="message" placeholder="Enter message">
<input type="submit">
</form>
<ul id="messages"></ul>
<script>
function sendMessage() {
// get message
var message = document.getElementById("message").value;
// send message to server
io.emit("send_message", {
sender: sender,
receiver: receiver,
message: message
});
// append your own message
var html = "";
html += "<li>You said: " + message + "</li>";
document.getElementById("messages").innerHTML += html;
// prevent form from submitting
return false;
}
// listen from server
io.on("new_message", function (data) {
var html = "";
html += "<li>" + data.sender + " says: " + data.message + "</li>";
document.getElementById("messages").innerHTML += html;
});
</script>
server.js
// listen from client inside IO "connection" event
socket.on("send_message", function (data) {
// send event to receiver
var socketId = users[data.receiver];
io.to(socketId).emit("new_message", data);
});
Open 2 browsers and choose different names for both browsers. Send a message from 1 browser to another and you will see new message on both browsers. You can see that you can chat with each other but when you refresh the page, all previous messages will be removed. That’s because we are not storing any message anywhere, they are just sent and received from one client to another.
When it comes to saving data, you have multiple choices. You can save data in relational database like MySQL, you can save in no-relational database like Mongo DB or you can save in files too in XML or JSON format.
Save messages in MySQL
Saving data in relational database is most easy and reliable among all mentioned above. So create a new database in your phpMyAdmin, you can select any name but for simplicity we have created a database named “web_chat”. Create a table named “messages” and it will have just 4 fields:
- ID INT AUTO INCREMENT
- sender TEXT
- receiver TEXT
- message TEXT
Now you need to install a module named “mysql” that will be used by Node JS server. So run the following command in your terminal:
npm install mysql
Don’t forget to start the server again after installing this module: “nodemon server.js”
To use this module in Node JS, first you have to create an instance of this module and create a connection with database. Finally you can connect with your database using connection object. So paste the following lines in your “server.js”:
server.js
// Create instance of mysql
var mysql = require("mysql");
// make a connection
var connection = mysql.createConnection({
"host": "localhost",
"user": "root",
"password": "",
"database": "web_chat"
});
// connect
connection.connect(function (error) {
// show error if any
});
To insert a new row in “messages” table, paste the following code in your “send_message” event in “server.js”:
// listen from client
socket.on("send_message", function (data) {
// send event to receiver
var socketId = users[data.receiver];
io.to(socketId).emit("new_message", data);
// save in database
connection.query("INSERT INTO messages (sender, receiver, message) VALUES ('" + data.sender + "', '" + data.receiver + "', '" + data.message + "')", function (error, result) {
//
});
});
If you try to send a message now, you will see that message in “messages” too. So the INSERT operation works, now we need to show all messages from previous chat when user selected.
Show previous private chat from database
In “index.php” change the “onUserSelected” function to the following:
function onUserSelected(username) {
// save selected user in global variable
receiver = username;
// call an ajax
$.ajax({
url: "http://localhost:3000/get_messages",
method: "POST",
data: {
sender: sender,
receiver: receiver
},
success: function (response) {
console.log(response);
var messages = JSON.parse(response);
var html = "";
for (var a = 0; a < messages.length; a++) {
html += "<li>" + messages[a].sender + " says: " + messages[a].message + "</li>";
}
// append in list
document.getElementById("messages").innerHTML += html;
}
});
}
It sends an AJAX request to the server sending the “sender” and “receiver” names as POST parameters, the response received in JSON so the response is parsed in Javascript objects. All messages will looped and appended in the list in the same way as appending in “sendMessage” function or in “send_message” event. In order to setup AJAX requests with POST method on Node JS server, we have to install a module named “body-parser” and we have to tell the Express instance and we will be encoding the URL. So install this module by running the following command in your terminal:
npm install body-parser
server.js
// create body parser instance
var bodyParser = require("body-parser");
// enable URL encoded for POST requests
app.use(bodyParser.urlencoded());
// enable headers required for POST request
app.use(function (request, result, next) {
result.setHeader("Access-Control-Allow-Origin", "*");
next();
});
// create api to return all messages
app.post("/get_messages", function (request, result) {
// get all messages from database
connection.query("SELECT * FROM messages WHERE (sender = '" + request.body.sender + "' AND receiver = '" + request.body.receiver + "') OR (sender = '" + request.body.receiver + "' AND receiver = '" + request.body.sender + "')", function (error, messages) {
// response will be in JSON
result.end(JSON.stringify(messages));
});
});
Headers will be used to allow your client to send AJAX requests. An API will be created that will fetch all previous messages between you and your selected user and send it back to client in JSON format. And your client is already parsing the JSON and displaying in a list so no need to make further changes in “index.php”.
Using MySQL with async/await
If you are planning to use async in MySQL module, you need to install the module named “mysql2/promise”.
npm install mysql2/promise
After installation, you can include it in your Node JS file.
const mysql = require("mysql2/promise")
const pool = mysql.createPool({
host: "localhost",
port: 3306,
user: "root",
password: "",
database: "db_name"
})
const connection = await pool.getConnection()
const [rows, fields] = await connection.query("SELECT * FROM users")
Note: Make sure to make the function async before using await command.
If you want to run the INSERT query and return the ID of the newly inserted row, you can do that by the:
const [result] = await connection.query(`INSERT INTO users (name) VALUES ('Adnan')`)
if (result) {
const userId = result.insertId
}
Go ahead and give it a free try, the design will not look good obviously, because we haven’t done anything on the design. But the functionality will be good enough for you to understand how private chat system works and how you can send message to specific user even when you have hundreds of users connected at the same time.
the source code of the app its shows only for one second then desapear , how can i get the code , than u
You need to register an account in order to download.
Im registered bro, and have the same problem, it only shows the second part, the sign up part for the users does not appear and I can not add users from de button ‘+’, great tutorial, can you help me? THANKS
Check your console using the inspect element. There must be some error in Javascript. And let me know the error.
i need a code please
You need to register an account in order to download.
i registered but i cant download
i dont have permission
You need to become a paid member to gain access to download source code.
The membership price is just $20 for lifetime.
body-parser deprecated undefined extended: provide extended option server.js:14:20
Yes, body-parser is deprecated, you need to use express-formidable module. Check this link for express formidable tutorial.