Build a web chat application using Node.js & socket.io
Tags: socket, node, chat, connect
Published: 2021-01-26 14:26:27

### Note worthy📝
* This article assumes that you already have node.js installed on your computer. If you haven't, kindly do so [here](https://nodejs.org/en/)

####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](https://dev-to-uploads.s3.amazonaws.com/i/eaf0gz2c1mu45gtezd8h.png)
* 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);
  });
```
* 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
    }
  });
```
* Use the socket object created earlier (io) to initiate the connection.
```
io.on('connection', socket => {
 
  });
``` 
* 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

  });
``` 
* 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

  });
``` 

* 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

  });
``` 
* 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 } 👂`));
```
* 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>
``` 
* 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>
```

* 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 } 👂`));

```
* 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')
```
* Connect to the front end to backend socket
```
// connect to the server socket
const socket = io('http://localhost:3000', {
  withCredentials: true
});
```
* 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}`)

    }
})
```
* 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`)
})
```
* 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)
```
* 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)
}
```
* 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 = ''
    }
  }
 
  
})

```
* 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](https://github.com/Joojo7/socket-application-server) and the front end out [here](https://github.com/Joojo7/socket-application-client)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/g075wupjczfpst65lkuk.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v0tsecygxvti8i2wl40j.png)