Build a Node.js command-line chat application with Chatkit
Building chat in your app can be pretty complex. Yet, with Chatkit, implementing fully-featured chat is nothing but a few lines of code.
In this tutorial, I’ll walk you through how to build a command-line chat, like this:
The complete code can be found on GitHub.
What is Chatkit?
You might be wondering, “what is Chatkit?”
In a nutshell, Chatkit is an API to help you build chat functionality in your app. Functionality like:
- Online presence
- Typing indicators
- Read indicators (unread message count, read receipts)
- Rich media messages
- And more
Additionally, Chatkit handles tricky details that come up when building real-time chat like reliability, and scale.
To me, using Chatkit means not having to deal with rolling a web socket server, managing infrastructure for it, and dealing with managing chat at scale!
In this tutorial, we’ll only touch the surface of what Chatkit can do. To give you an idea of what you can build, check out this open source Slack clone, powered by Chatkit:
Pretty neat, right?
Create a Chatkit instance
Before diving into the tutorial, you should setup a Chatkit instance. It only takes a second.
To create one, head to pusher.com/chatkit and click Sign Up. Within the dashboard, beneath “Chatkit”, hit Create new + then enter a name for the instance. I called mine “My Awesome Chatkit App!”:
Within the Keys tab, take note of your Instance Locator and Secret Key. We’ll need these in a moment.
Create a Chatkit room
Chatkit enables us to create public or private chat rooms, and even supports one-to-one chat.
Normally, you’d create rooms dynamically — for example, when an end user creates a new room—but in this tutorial we’ll the Inspector to create one manually:
Create an authentication server
Authentication is the action of proving a user is who they say they are. Normally, this involves a password.
In this tutorial, we won’t authenticate users —we won’t ask them for a password — but we’ll still need to write an
/authenticate route that returns a Chatkit token.
Additionally, we’ll need to define a route called
/users that creates a Chatkit user.
To do this, create a new folder, I called mine
terminal-chat. Then, install
express, and some Express middleware:
npm init -y
npm install --save @pusher/chatkit-server npm install --save express npm install --save body-parser cors
Then, create a new file called
server.js and paste in the following code:
Remember to replace
YOUR_CHATKIT_KEY with your own.
Setup our client
Now we have a server and a Chatkit instance, we can start building the command-line client.
In the same project, install
npm install --save @pusher/chatkitnpm install --save jsdom
To be clear, in the previous step, we installed the Chatkit server SDK (
@pusher/chatkit-server) and here, we install the client Chatkit SDK (
@pusher/chatkit-client). We also installed
jsdom, but more on that in a moment.
In a new file called
client.js, paste the following:
Starting at the top, we first import
@pusher/chatkit. We’ll reference these soon.
We also import
jsdom, the dependency I mentioned earlier.
In a nutshell,
@pusher/chatkit-client works in the browser but not in Node. In a function called
makeChatkitNodeCompatible, we use
jsdom to “trick” Chatkit into thinking it’s running in the browser ?. This is a temporary workaround, but it works perfectly.
At the bottom of the module, we define an
async function called
main, which enables us to use
await when calling asynchronous functions.
await is a new concept to you, here’s a great introduction.
Prompt the user for their username
Before we can allow a user to join a room, we need prompt them for their name. To do this, we can use
npm install --save prompt
And then, import it:
Then, update our main function:
Now, if we run the app with the command
node client.js, we should have our prompt:
Create a user
Before connecting to Chatkit, we must first create a Chatkit user via the server we wrote earlier.
To do this, we’ll send a request to the
/users route using
axios, which is a HTTP client:
npm install --save axios
axios, import it:
Then, define a function called
We can now call this function with the prompted username:
Let’s test this out.
Open two terminal windows. In one, start the server with
node server.js and in the other, run the client with
node client.js. If all is well, you should be prompted for a username, and you’ll see
User created: <username> in the server output.
If you see an error along the lines of
Failed to create a user, connect ECONNREFUSED then your server might not be running, so double check that.
Setup the Chatkit SDK
At this point, we have a username and the ability to create a user. Next, we’ll want to connect to Chatkit as that user.
To do this, beneath the call you just made to
createUser, paste the following:
Again, remember to replace your
YOUR_INSTANCE_LOCATOR with the Instance Locator you noted earlier.
This code initialises Chatkit then connects to the service, returning the
currentUser. Note how we provide a
TokenProvider which points to our authentication server.
Now we have an authenticated user, we can show them a list of rooms they can join.
To do this, we should update the main function in
client.js to fetch joinable rooms (
getJoinableRooms), and list them alongside the rooms a user has already joined (
... syntax there is called destructuring, and it provides a succinct way to merge two or more arrays.
node client.js should now print out a list of rooms:
You’ll probably just see one room to start with. To create additional rooms, go back to the Inspector or use the the
Subscribe to a room
Next, we should prompt the user to pick a room, with this code:
One cool thing about
prompt is that you can create validation rules. Above, we create one to make sure the user’s input is between
0 and the number of joinable rooms.
Once we have the user’s room choice, we can set that as the
room and subscribe to the room:
Upon subscribing, we add a
You can think of a hook as a function that is called whenever an event occurs. In this case it’s when a new message is received.
onNewMessage will be called in real-time whenever a new message is sent by “a user”. When I say “a user”, that includes the current user, so within the function we only print the message if it was sent by someone else.
Send messages from user input
Being able to receive messages isn’t much use if we can’t also send messages now, is it?
Fortunately, sending a message is but one line of code with Chatkit.
readline to read input from the user:
npm install --save readline
Then, import it:
Finally, reference it below:
If you run two instances of the client, you should be able to send and receive messages:
Add a loading spinner for a bit of fun ✨
As ever, sending data over the network might take a second or two. For a bit of fun, and to make our application feel faster, let’s add a nifty loading spinner:
ora, a loading spinner module:
npm install --save ora
client.js,we can call
succeed, etc. depending on the status of the command.
Here’s the complete
client.js file, with the new spinner-related code highlighted:
Amazing, we’re done!
To recap, you learned how to:
- Prompt and authenticate the user
- Connect to Chatkit
- List the users available rooms
- Join a room
- Send and receive messages from a room
- And, for fun, add a loading spinner
In this tutorial, we barely touched the surface of Chatkit. There’s so much more we could build, including:
- Switch between rooms
- Create new rooms
- Show users offline/offline status
- Show typing indicators
- Show read receipts
Want to learn how? Let me know in the comments and we’ll write part 2.
Alex Booker created a video tutorial based on this article. Check it out!