DEV Community

Cover image for Build a web chat application using Node.js & socket.io
JOOJO DONTOH
JOOJO DONTOH

Posted on • Edited on

Build a web chat application using Node.js & socket.io

Note worthy📝

  • This article assumes that you already have node.js installed on your computer. If you haven't, kindly do so here

Lets begin!

This write up hopes to walk you through the process of building a very simple 2 layer chat application.

Lets start by building the backend
  • Create a folder and name it whatever you want, I'll be naming mine SOCKET-APPLICATION-SERVER.
  • Now you can use any IDE of your choice to open the folder. I prefer to use VScode.
  • Open the terminal in this folder and initiate your node project with npm init. This command compiles all the main details of the your application such as name, version, description etc into a package.json file. Alt Text
  • Now create your entry point file and give it a name of your choice. I'll name mine app.js.
  • Download the socket.io package by by running npm install socket.io in the terminal.
  • set up your server in the the app.js file with the code below.
const httpServer = require('http').createServer((req, res) => {
    res.setHeader('Access-Control-Allow-Origin', `${front end server link}`);
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', true);
  });
Enter fullscreen mode Exit fullscreen mode
  • Now require the socket.io package and create an object from it.
 const io = require('socket.io')(httpServer, {
    cors: {
      origin: `${front end server link}`,
      methods: ["GET", "POST"],
      credentials: true
    }
  });
Enter fullscreen mode Exit fullscreen mode
  • Use the socket object created earlier (io) to initiate the connection.
io.on('connection', socket => {

  });
Enter fullscreen mode Exit fullscreen mode
  • Now we are going receive the user's name entry from the frontend (this will make a lot more sense when we start building the frontend).
io.on('connection', socket => {

//new code added
   socket.on('username', username => {
      users[socket.id] = username
      socket.broadcast.emit('user-in', username)
    })
//new code added

  });
Enter fullscreen mode Exit fullscreen mode
  • Since we now how the user's name after they connect, we can now worry about the user's (sender) message. We going to broadcast the user's (sender) message with to anyone one else online. We will do this by first receiving the message that tagged with send-chat-message then emit it with a chat-message tag. The tages help to distinguish between the messages coming in and those going out.
io.on('connection', socket => {

   socket.on('username', username => {
      users[socket.id] = username
      socket.broadcast.emit('user-in', username)
    })

//new code added
  socket.on('send-chat-message', msg => {
        socket.broadcast.emit('chat-message', {message: msg, 
  name: users[socket.id]})
    })
//new code added

  });
Enter fullscreen mode Exit fullscreen mode
  • We would like to notify the receiver once the sender disconnects or vice-versa.
  const users = {}
io.on('connection', socket => {

   socket.on('username', username => {
      users[socket.id] = username
      socket.broadcast.emit('user-in', username)
    })

 socket.on('send-chat-message', msg => {
        socket.broadcast.emit('chat-message', {message: msg, 
  name: users[socket.id]})
    })

//new code added
 socket.on('disconnect', () => {
      socket.broadcast.emit('user-disconnected', users[socket.id])
      delete users[socket.id]
    })
//new code added

  });
Enter fullscreen mode Exit fullscreen mode
  • Finally set the port for the server and listen for requests
  const PORT = process.env.PORT || 3000;
  httpServer.listen(PORT, () => console.log(`Running server on 🚀. \nListening on ${ PORT } 👂`));
Enter fullscreen mode Exit fullscreen mode
  • Start the server by running node app.js in the terminal. You can consider using nodemon which automatically refreshes your server anytime you make a change.

Lets start building the frontend

To aid with proper understanding the front end will run on a separate server.

  • Create a folder and name it whatever you want, I'll be naming mine SOCKET-APPLICATION-CLIENT.
  • Open the folder in your IDE.
  • Run npm init in the terminal for this folder
  • Download the socket.io package by by running npm install socket.io in the terminal.
  • create a simple index.html file with the following body.
<body>
        <div id="message-container">
        </div>

            <div  id="send-container">

                <input name=""  placeholder="Type your message..." type="text" id="message-input"> 
                <button id="end-button"  type="submit">
                    <span  id="submits">
                        <i class="fas fa-location-arrow"></i>
                    </span>
                </button> 
            </div>

    </body>
Enter fullscreen mode Exit fullscreen mode
  • Add the following script links inside your index.html <head> tag. The socket.io instance will be created and sent from the backend. The script.js file will use the instance to send and receive messages.
<script defer src="http://localhost:3000/socket.io/socket.io.js"></script>
<script defer src="./script.js"></script>
Enter fullscreen mode Exit fullscreen mode
  • Also download the nodemon package by by running npm install nodemon in the terminal. This will restart your frontend server anytime you make a changes.
  • Now create your entry point file: app.js.
  • Set up your server in the the app.js by first running npm install express. We'll need express to server static files like our index.html page.
  • Now fill the app.js page with the code below.
var express = require('express'), app = express() 
app.use('/', express.static('public'));

const PORT = process.env.PORT || 8000;
app.listen(PORT, () => console.log(`Running server on 🚀. \nListening on ${ PORT } 👂`));

Enter fullscreen mode Exit fullscreen mode
  • Create the scripts.js file we linked to the index.html earlier. In the file, start by getting all the need DOM elements.

const mesaageForm = document.getElementById("submits")
const messageInput = document.getElementById('message-input')
const messageContainer = document.getElementById('message-container')
const userInfo = document.getElementById('user-info')
Enter fullscreen mode Exit fullscreen mode
  • Connect to the front end to backend socket
// connect to the server socket
const socket = io('http://localhost:3000', {
  withCredentials: true
});
Enter fullscreen mode Exit fullscreen mode
  • Allow the socket to listen for messages. Only append the message to the receiver's view if it is not empty
//listen to the socket for content with the tag 'chat-message'
socket.on('chat-message', data => {
    if (data.message != "") {
      appendMessage(`${data.name}: ${data.message}`)

    }
})
Enter fullscreen mode Exit fullscreen mode
  • Since we want to notify the receiver if sender disconnects or vice versa, we will use the socket to listen for disconnections.
//listen to the socket for user disconnection
socket.on('user-disconnected', name => {
  appendMessage(`${name}: disconnected`)
})
Enter fullscreen mode Exit fullscreen mode
  • Now that our application is listening for all the necessary changes and messages, we can move on to obtaining the user's name
//ask the user for their name
const username = prompt('What is your name ?😃')
socket.emit('username', username)
Enter fullscreen mode Exit fullscreen mode
  • Now we need to write functions that will append new messages to the screen for both the sender and receiver.
// send message to reciever
function appendMessage(message){
  let man = messageContainer.scrollHeight + 500;
  messageContainer.scroll = man
  var wrapper= document.createElement('div');
wrapper.innerHTML = `

    <div>
      <p>${message}</p>
    </div>
              `
      messageContainer.append(wrapper)
}

//show message on sender's screen
function appendMessageForMe(message){
  messageContainer.scrollTop = messageContainer.scrollHeight;

  var wrapper= document.createElement('div');
wrapper.innerHTML = `
  <div>
      <p>${message}</p>
    </div>
              `
      messageContainer.append(wrapper)
}
Enter fullscreen mode Exit fullscreen mode
  • Finally we are going to use the event listener to activate the functions we just created whenever the user wants to send a message. To make things easier, we will activate the function when the user taps/clicks the send button, or presses the enter button after they have typed a message.

// if the user taps the send button or presses enter key, the message should be sent.
mesaageForm.addEventListener('click', e =>{
    e.preventDefault()
    const message  = `${messageInput.value}`
    if (message != "") {

      // the emit method sends the message out with the tag: 'send-chat-message' 
      socket.emit('send-chat-message', message)
      appendMessageForMe(message)
      messageInput.value = ''
    }

})
messageInput.addEventListener('keydown', e =>{
  if (e.key === "Enter") {
    e.preventDefault()
    const message  = `${messageInput.value}`
    if (message != "") {
      socket.emit('send-chat-message', message)
      appendMessageForMe(message)
      messageInput.value = ''
    }
  }


})

Enter fullscreen mode Exit fullscreen mode
  • Run nodemon in the terminal and go to http://localhost:8000/
  • Don't forget to also run the backend server.

Conclusion

  • we built a backend server that uses socket.io to recieve and reroute our messages to available users
  • we also built a very simple 😅 frontend to demonstrate the exchange of messages
  • Don't forget to add your enhancements after you try this. I have an advanced version of this application on my repository. Check the backend out here here and the front end out here Alt Text Alt Text

Top comments (0)