Understanding the basics of Socket.io
Tags: node, javascript, beginners
Published: 2019-12-05 17:41:39

---
title: Understanding the basics of Socket.io
published: true
description: a step by step guide to understand how a socket.io application works and the understand the client and server responsabilities
tags: nodejs, javascript, beginners
---
<p><em>This article was originally posted in <a href="https://www.antonioufano.com" target="_blank">my website</a>. If you like it, you may find interesting previous articles in <a href="https://www.antonioufano.com/blog" target="_blank">my blog</a></em><p>
<hr>

<p>After doing a lot of APIs and microservices lately, I've been trying to find new ideas for quick demos to improve my skills. In one of the projects I'm working on, I'm planning to include a feed that is refreshed with the activity of the users in real time. I wasn's sure about how to do it and, at first I thought about using RabbitMQ, but after a quick search I found WebSockets and <a href="https://socket.io/" title="socket.io page" target="_blank">Socket.io</a>. If you want to learnt what WebSockets are, watch <a href="https://www.youtube.com/watch?v=ZbrEztkwcw8" title="websockets explained" target="_blank">this super quick video</a> to understand the basic concepts. <br></p><p>Instead of builing directly the user's feed for my project, I decided to build a quick chat demo first. There are multiple articles and videos that explain how to create a chat
 with socket.io but most of them don't explain exactly how all involved parts 
work together or are just a small demo to run locally but 
is not "deployable" to production. So I took all those examples as references to build my chat, took notes of everything that wasnt clear for me and built it in a way so it can be deployed to a server (even created a Docker image!). Here are all my notes.</p><h3>Chat server and client responsabilities<br></h3><p>Our chat app server will have following responsabilities:</p><ul><li>Serve the HTML/CSS/JS client files to the users</li><li>Start Socket.io connection</li><li>Serve socket.io library to the clients (optional as clients can also load it from a CDN)</li><li>Broadcast events (like a new chat message) to all clients connected</li></ul><p>When a user connects to our server from his browser, he'll receive the HTML/CSS/JS client files which will:</p><ul><li>Load socket.io client library (from our server or from a CDN)</li><li>Stablish connection with the Socket.io running in our server</li><li>Ask user to enter his name so we can identify him in the chat<br></li><li>Emit and receive events to/from Socket.io running in our server</li><li>Add our own messages to the chat via JavaScript</li></ul><br><h3>Chat server in detail</h3><p>First thing is to start our Node.js project with <em>"npm init"</em> as we'd have to install dependencies later. We can use Node's http module to create a static server that sends our client any type of files, in our case it would be html, css and js. I found <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Node_server_without_framework" title="node server mozilla docs" target="_blank">this example</a> in the Mozilla docs which was exactly what I was looking for. No framework, just an http server able to send html, css, js, images and more. They also explain how it works line by line so I'll not go into that. I put the server code in a file named server.js. The only things I changed from the Mozilla example are the port number and the path were it reads the files from, as I'll use a folder named "client":</p><pre><code class="language-javascript">var filePath = './client' + request.url;
console.log(filePath)
if (filePath == './client/') {
  filePath = './client/index.html';
}
</code></pre><br>
<p>Next step was to install the socket.io dependency with "<em>npm i socket.io</em>" include it in our server.js file and log something when we detect a connection:</p><pre><code class="language-javascript">var io = require('socket.io')(app);
// starts socket
io.on('connection', function (socket) {
  console.log('Socket.io started.....')
  // Manage all socket.io events next...
    socket.on('new-connection', (data) =&gt; {
    // captures event when new clients join
    console.log(`new-connection event received`)
    .........
  })
});
</code></pre>

<p>I've also included how to capture an event called 'new-connection', which for now, will just print something in the console. Now let's move to the client.</p>

<h3>Chat client in detail</h3>
<p>As mentioned earlier, I placed all our client files (html, css and js) in a folder named <em>client</em>. The index.html file is pretty simple: <br></p>
<ul>
<li>in the header we're loading the socket.io client library, from a CDN although I've also included the code to load it from our own server</li>
<li>also in the header, we load our script.js file.</li>
<li>the body only contains a div container for all the chat messages and a form to submit new ones.</li></ul>

<p>You can find the code of the index.html file in <a href="https://gist.github.com/uF4No/5303f07fab1223690d353addcacdcdf7" target="_blank">this GitHub Gist</a> or directly in <a href="https://github.com/uF4No/chat-socket.io" target="_blank">the repo</a>.</p> 

<p>
<script src="https://gist.github.com/uF4No/5303f07fab1223690d353addcacdcdf7.js"></script>
</p>

<p>In the client <em>script.js</em> file, the first thing I did was to connect via socket.io from the client to the server. As I'm loading the socket.io library before the script.js file, I have it available so I can use the <strong><em>io()&nbsp;</em></strong> function to create a socket connected to the server and the <strong><em>emit()</em> function to send a basic event</strong> named <em>'new-connection'</em> and the name of the user:<br></p><pre><code class="language-javascript">/**
 * Use io (loaded earlier) to connect with the socket instance running in your server. 
 * IMPORTANT! By default, socket.io() connects to the host that 
 * served the page, so we dont have to pass the server url
 */
var socket = io();

//prompt to ask user's name 
const name = prompt('Welcome! Please enter your name:')

// emit event to server with the user's name
socket.emit('new-connection', {username: name})

</code></pre><p>At this point, if I start the server using '<em>node server.js</em>' and open the browser I get the prompt and after entering the name, I'll be connected to the socket server and see something like this in the server console:</p><pre><code class="language-javascript">
$ npm start

&gt; chatsocket.io@1.0.0 start /d/Projects/chatSocket.io
&gt; node server.js

HTTP Server running at http://127.0.0.1:3000/
request  /
./client/
request  /script.js
./client/script.js 
request  /style.css
./client/style.css
Socket.io started.....
request  /favicon.ico
./client/favicon.ico

</code></pre><p>Up to this point, I was able to:</p><ul><li>start a static server that sends the client files and opens the socket.io connection</li><li>connect the clients to the server via socket.io and emit an event called 'new-connection'</li><li>capture the 'new-connection' event in the server and print it to the console</li></ul><p>The only things missing to complete the chat application were:</p><ul><li>being able to link messages with the user's names<br></li><li>add messages we send to the chat-container div<br></li><li>emit event to the server containing the message sent<br></li><li>broadcast chat messages received in the server to all clients connected<br></li></ul><p>Adding the messages we send to the chat-container div is something we can do in the client <em>script.js</em> file. We just need to add an event listener to capture when the form is submitted and, whenever that happens, create a new div containing the message inside the chat-container. As this is something I'll have to do also when we receive messages from other users, I created a function called <em>addMessage(data, type) </em>which I can call multiple times. In addition, I trigger an event called 'new-message' sending to the server an object with both the message and the client's socket id.<br></p><pre><code class="language-javascript">
// get elements of our html page
const chatContainer = document.getElementById('chat-container')
const messageInput = document.getElementById('messageInput')
const messageForm = document.getElementById('messageForm')

messageForm.addEventListener('submit', (e) =&gt; {
  // avoid submit the form and refresh the page
  e.preventDefault()
  // check if there is a message in the input
  if(messageInput.value !== ''){
    let newMessage = messageInput.value
    //sends message and our id to socket server
    socket.emit('new-message', {user: socket.id, message: newMessage})
    addMessage({message: newMessage}, 'my' )
    //resets input
    messageInput.value = ''
  }
})

// receives two params, the message and if it was sent by you
// so we can style them differently
function addMessage(data, type){
  const messageElement = document.createElement('div')
  messageElement.classList.add('message')

  if(type === 'my'){
    messageElement.classList.add('my-message')
    messageElement.innerText = `${data.message}`

  }else if(type === 'others'){
    messageElement.classList.add('others-message')
    messageElement.innerText = `${data.user}: ${data.message}`

  }else{
    messageElement.innerText = `${data.message}`

  }
  // adds the new div to the message container div
  chatContainer.append(messageElement)
}
</code></pre><p>Note that I also added different styles to the messages depending if they belong to the user or if they are received from others.</p><p>Next step is to handle the 'new-connection' and 'new-message' events properly in our <em>server.js</em>. In the 'new-connection' event I stored the client's socket id and the user name as key:values of an object named<em> users</em>. Then in the 'new-message' event, I used the socket id received to find the correspondent user name, and with the <strong><em>broadcast()</em> function, send the message information to all clients connected except the one that emitted the event originally</strong>.<em><br></em></p><pre><code class="language-javascript">
// we'll store the users in this object as socketId: username
const users = {}

var io = require('socket.io')(app);
// starts socket
io.on('connection', function (socket) {
  console.log('Socket.io started.....')
  // Manage all socket.io events next...
  socket.on('new-connection', (data) =&gt; {
    console.log(`new-connection event ${data.username}`)
    // adds user to list
    users[socket.id] = data.username
    socket.emit('welcome', { user: data.username, message: `Welcome to this Socket.io chat ${data.username}` });
  })
  socket.on('new-message', (data) =&gt; {
    console.log(`new-message event ${data}`);
    // broadcast message to all sockets except the one that triggered the event
    socket.broadcast.emit('broadcast-message', {user: users[data.user], message: data.message})
  });
});
</code></pre>

<p style="text-align: left;">With these last few bits done, I had a fully functional chat application and I could test it by opening multiple browsers locally: <br></p><p style="text-align: center;"><a href="https://www.antonioufano.com/image_uploads/chats.PNG"><img src="https://www.antonioufano.com/image_uploads/chats.PNG" alt="chat app" width="30%"></a></p>

<p>The only thing I havent covered up until now is the styling (which you can find in the <a href="https://github.com/uF4No/chat-socket.io/blob/master/client/style.css" title="styles file" target="_blank">style.css file</a>) and minor validations, like making sure users cannot send empty messages. You can find the full code in <a href="https://github.com/uF4No/chat-socket.io" title="code repo" target="_blank">this repo in GitHub</a>. It also contains a Dockerfile so you can build an image and deploy it anywhere with Docker 🙃 or if you just want to try it online, visit <a href="http://chatsocket-demo.eu-west-1.elasticbeanstalk.com/">this link</a>.</p>

<p>For this app I just needed to use the emit() and broadcast() functions but Socket.io contains a lot more functionalities like assign namespaces to sockets so they have different endpoints, create rooms and even integrate it with Redis. You can find examples of all those in <a href="https://socket.io/docs/" title="socket.io documentation" target="_blank">the docs</a>. <br></p><p>Hope this helps you understand WebSockets and how Socket.io works.</p><p>Happy coding!<br></p>