WebSockets are a fascinating technology, a TCP-based network protocol that allows for asynchronous bi-directional communication. The client starts a connection, sends a request and gets a response – just like HTTP. But much unlike HTTP this connection is kept alive! This has many advantages, like
- Faster responses (no re-establishing connections)
- Less trafic (no overhead for HTTP-headers)
- Live updates (no periodic polling, but push notifications)
If you want to learn more about WebSockets, I recommend this introduction. In this post we’re focussing on utilizing WebSockets to build a simple chat application.
Prerequisites
We’re building this project on top of the Hello NodeJS Tutorial Series, so we can focus exclusively on adding chat-functionality.
Socket.IO
To make working with WebSockets a breeze, there’s a project called ‘socket.io’ that provides a convenient wrapper for it. And of course, there’s an npm package for it as well!
|
|
While we’re at it, let’s also install another package that allows us to work with the express-session in the socket.io context:
|
|
In server.js
we tell the server that we would like to use those packages like so:
|
|
In order to have changes we make to the session in socket.io available in express-session as well, we need this piece of code:
|
|
Listen And Emit
Now here is where the fun really kicks off:
|
|
When socket.io detects a new connection, it executes this function. First it grabs the name of the currently logged in user from the session and writes it to console. It then sends a broadcast telling everyone about the new guy in town and greets the user itself. Using socket.broadcast.emit
sends messages to everyone BUT the current user, while socket.emit
sends messages to ONLY the current user. You can also send messages to ALL connected clients by calling io.emit()
.
The first parameter can be considered the “group” of the message. This is so the receiver(s) can handle different groups differently (it gets clearer with the JavaScript implementation in a moment!). The second parameter is of course the message itself.
When the user disconnects, there’s a console entry again as well as a broadcast to inform all users (except the one disconnecting) about what’s happening.
Same behaviour on chat messages coming in: “Broadcast the message to all connected clients but the one sending it!”
Notice how socket.io is not just capable of transmitting plain text but also JSON-Objects. When the server receives a chat message, it manipulates the content by adding the sender’s username.
Let that sink in! If you’re like me and get confused about all this broadcast.emit
, socket.emit
, io.emit
stuff, here’s a nice little Cheatsheet from the official docs to help you!
Adding A Route
Before we continue with the client-part of socket.io, let’s add a route for our chat! Remember: we manage our routes in the controllers
folder. In there we add a file called chat.js
and write the following to it:
|
|
If you followed my Hello NodeJS Tutorial, this should look familiar. All we do is check if the user is logged in and if so, render the chat view. Of course, for this route to take effect, we have to add it to controllers/index.js
:
|
|
And since we’re here, lets’s also redirect requests to the main page to the chat:
|
|
Adding A View
After we’ve got our route installed, we need to make sure there’s actually content to be found there! For that we create a view for our chat. We do this by creating a folder views/chat/
and a file index.hbs
inside that folder with the following content:
|
|
There’s nothing special in this markup, just a container for messages, an input box for adding new ones, a box to display the user’s name (we passed that in here using the render()-function in our chat-route) and a link to log out.
The styling for this page can be found in public/css/design.css
. It’s quite long, so I won’t put it here as it would only distract from the essential code.
Sending Messages
Remember the code block in server.js
where messages were distributed by the server? Here comes the client part in public/js/chat.js
! First, this is how we send messages:
|
|
With the socket instance we emit messages (send to everyone but ourself).
Displaying the message in our chat-box is handled seperately in addMessage()
|
|
This basically just formats and adds the message to the chat-box.
Receiving Messages
We don’t want to talk to ourselves, do we? So let’s see how we handle incoming messages:
|
|
This is, where the message “types” come into play. Depending on the type of the message we display them with different colors. Also, when the client receives a ‘chat message’ it expects a JSON-Object and extracts the actual message body and the sender’s username from it.
Conclusion
There we go! A basic chat application using NodeJS and WebSockets with Socket.IO. Check out the final project on GitHub!