In this tutorial, you will learn how to create a group chat app. You will build a backend app using Node.js that will make group chats, authorize chat participants, and maintain sessions for them. The front-end will be built using Vanilla JS, HTML and CSS. It will allow users to log in, make new groups, invite friends, and trade messages. By the end, you should have a working app where multiple participants can send messages in one group.
Chat is becoming an increasingly popular communication medium in both business and social contexts. Businesses use chat for customer and employee intra-company communication like with Slack, Microsoft Teams, Chanty, HubSpot Live Chat, Help Scout, etc. Most social networks and communication apps also offer chat as an option by default, like on Instagram, Facebook, Reddit, and Twitter. Other apps like Discord, Whatsapp, and Telegram are mostly chat-based, with group chats being one of their main functionalities.
While there exist numerous products to facilitate chat, you may need a custom-tailored solution for your site that fits your particular communication needs. For example, many of these products are stand-alone apps and may not be able to integrate within your own site. Having your users leave your website to chat may not be the greatest option as it can affect user experience and conversion. On the flip side, building a chat app from scratch can be a daunting and sometimes overwhelming task. However, by using APIs like Twilio Conversations you can simplify the process of creating them. These communication APIs handle group creation, adding participants, sending messages, notifications, among other important chat functions. Backend apps that use these APIs only have to handle authentication and make calls to these APIs. Front-end apps then display conversations, groups, and messages from the backend.
In this tutorial, you will learn how to create a group chat app using the Twilio Conversations API. The front end for this app will be built using HTML, CSS, and Vanilla JavaScript. It will allow users to create group chats, send invites, login, as well as send and receive messages. The backend will be a Node.js app. It will provide authentication tokens for chat invitees and manage chat creation.
Prerequisites
Before you can start this tutorial, you need to have the following:
- Node.js installed. You’ll use it primarily for the backend app and to install dependencies in the front-end app.
You can get it using a pre-built installer available on the Node.js downloads page. - A Twilio account.
You can create one on the Twilio website at this link. http-server
to serve the front-end app.
You can install it by runningnpm i -g http-server
. You can also run it withnpx http-server
for one-off runs.- MongoDB for session storage in the backend app.
Its installation page has a detailed guide on how to get it running.
The Backend App
To send chat messages using Twilio API, you need a conversation. Chat messages are sent and received within a conversation. The people sending the messages are called participants. A participant can only send a message within a conversation if they are added to it. Both conversations and participants are created using the Twilio API. The backend app will perform this function.
A participant needs an access token to send a message and get their subscribed conversations. The front-end portion of this project will use this access token. The backend app creates the token and sends it to the frontend. There it will be used to load conversations and messages.
Project Starter #
You’ll call the backend app twilio-chat-server
. A scaffolded project starter for it is available on Github. To clone the project and get the starter, run:
The backend app takes this structure:
To run the app, you’ll use the node index.js
command.
Dependencies
The backend app needs 8 dependencies. You can install them by running:
Here’s a list of each of the dependencies:
connect-mongo
connects to MongoDB, which you’ll use as a session store;cors
handles CORS;dotenv
loads environment variables from the.env
file that you will create in a later step;express
is the web framework you’ll use for the backend;express-session
provides middleware to handle session data;http-errors
helps create server errors;morgan
handles logging;twilio
creates the Twilio client, generates tokens, creates conversations, and adds participants.
Configuration
The config
folder is responsible for loading configuration from environment
variables. The configuration is grouped into three categories:
configuration for CORS, Twilio, and the MongoDB session DB. When the
environment is development
, you will load config
from the .env
file using dotenv
.
Start by creating the .env
file on the terminal. This file is already added to the .gitignore
file to prevent the sensitive values it contains from being checked into the repository.
Here’s what your .env
should look like:
You can learn how to create a user for your session DB from this MongoDB manual entry. Once you create a session database and a user who can write to it, you can fill the SESSION_DB_USER
, SESSION_DB_PASS
, and SESSION_DB_NAME
values. If you’re running a local instance of MongoDB, the SESSION_DB_HOST
would be localhost
, and the SESSION_DB_PORT
usually is 27017
. The SESSION_DB_SECRET
is used by express-session to sign the session ID cookie, and it can be any secret string you set.
In the next step, you will get credentials from the Twilio Console. The credentials should be assigned to the variables with the TWILIO_
prefix. During local development, the front-end client will run on http://localhost:3000. So, you can use this value for the CORS_CLIENT_DOMAIN
environment variable.
Add the following code to config/index.js
to load environment variables.
The environment variables are grouped into categories based on what they do. Each of the configuration categories has its own object variable, and they are all exported for use in other parts of the app.
Getting Twilio Credentials From the Console
To build this project, you’ll need four different Twilio credentials: an Account SID, an Auth Token, an API key, and an API secret. In the console, on the General Settings page, scroll down to the API Credentials section. This is where you will find your Account SID and Auth Token.
To get an API Key and Secret, go to the API Keys page. You can see it in the screenshot below. Click the + button to go to the New API Key page.
On this page, add a key name and leave the KEY TYPE
as Standard
, then click Create API Key. Copy the API key and secret. You will add all these credentials in a .env
file as you shall see in subsequent steps.
The backend app needs two utility functions. One will create a token, and the other will wrap async controllers and handle errors for them.
In utils/token.js
, add the following code to create a function called createToken
that will generate Twilio access tokens:
In this function, you generate access tokens using your Account SID, API key, and API secret. You can optionally supply a unique identity which could be a username, email, etc. After creating a token, you have to add a chat grant to it. The chat grant can take a conversation service ID among other optional values. Lastly, you’ll convert the token to a JWT and return it.
The utils/controller.js
file contains an asyncWrapper
function that wraps async controller functions and catches any errors they throw. Paste the following code into this file:
Controllers #
The backend app has four controllers: two for authentication and two for handling conversations. The first auth controller creates a token, and the second deletes it. One of the conversations controllers creates new conversations, while the other adds participants to existing conversations.
Conversation Controllers #
In the controllers/conversations.js
file, add these imports and code for the StartConversation
controller:
The StartConversation
controller first creates a Twilio client
using your twilioConfig.accountSid
and twilioConfig.authToken
which you get from config/index.js
.
Next,
it creates a conversation. It needs a conversation title for this,
which it gets from the request body. A user has to be added to a
conversation before they can participate in it. A participant cannot
send a message without an access token. So, it generates an access token
using the username provided in the request body and the conversation.chatServiceSid
.
Then the user identified by the username is added to the conversation.
The controller completes by responding with the newly created
conversation and participant.
Next, you need to create the AddParticipant
controller. To do this, add the following code below what you just added in the controllers/conversations.js
file above:
The AddParticipant
controller adds new participants to already existing conversations. Using the conversationSid
provided as a route parameter, it fetches the conversation. It then
creates a token for the user and adds them to the conversation using
their username from the request body. Lastly, it sends the conversation
and participant as a response.
Auth Controllers #
The two controllers in controllers/auth.js
are called GetToken
and DeleteToken
. Add them to the file by copying and pasting this code:
The GetToken
controller retrieves the token and username from the session if they exist and returns them as a response. DeleteToken
deletes the session.
Routes #
The routes
folder has three files: index.js
, conversations.js
, and auth.js
.
Add these auth routes to the routes/auth.js
file by adding this code:
The GET
route at the /
path returns a token while the DELETE
route deletes a token.
Next, copy and paste the following code to the routes/conversations.js
file:
In this file, the conversations router is created. A POST
route for creating conversations with the path /
and another POST
route for adding participants with the path /:id/participants
are added to the router.
Lastly, add the following code to your new routes/index.js
file.
By adding the conversation
and auth
routers here, you are making them available at /api/conversations
and /auth/token
to the main router respectively. The router is then exported.
The Backend App #
Now it’s time to put the backend pieces together. Open the index.js
file in your text editor and paste in the following code:
This file starts off by creating the express app. It then sets up JSON and URL-encoded payload parsing and adds the logging middleware. Next, it sets up CORS and the session handling. As mentioned earlier, MongoDB is used as the session store.
After all that is set up, it then adds
the router created in the earlier step before configuring error
handling. Lastly, it makes the app listen to and accept connections at
the port specified in the .env
file. If you haven’t set the port, the app will listen on port 8000
.
Once you’re finished creating the backend app, make sure MongoDB is running and start it by running this command on the terminal:
You pass the NODE_ENV=development
variable, so that configuration is loaded from the local .env
file.
The Front-end
The front-end portion of this project serves a couple of functions. It allows users to create conversations, see the list of conversations they are a part of, invite others to conversations they created, and send messages within conversations. These roles are achieved by four pages:
- a conversations page,
- a chat page,
- an error page,
- a login page.
You’ll call the front-end app twilio-chat-app
. A scaffolded starter exists for it on Github. To clone the project and get the starter, run:
The app takes this structure:
The styling and HTML markup have already been added for each of the pages in the starter. This section will only cover the scripts you have to add.
Dependencies #
The app has two dependencies: axios
and @twilio/conversations
. You’ll use axios
to make requests to the backend app and @twilio/conversations
to send and fetch messages and conversations in scripts. You can install them on the terminal by running:
The Index Page
This page serves as a landing page for the app. You can find the markup for this page (index.html
) here. It uses two CSS stylesheets: styles/main.css
which all pages use and styles/simple-page.css
which smaller, less complicated pages use.
You can find the contents of these stylesheets linked in the earlier paragraph. Here is a screenshot of what this page will look like:
The Error Page
This page is shown when an error occurs. The contents of pages/error.html
can be found here. If an error occurs, a user can click the button to go to the home page. There, they can try what they were attempting again.
The Conversations Page
On this page, a user provides the title of a conversation to be created and their username to a form.
The contents of pages/conversation.html
can be found here. Add the following code to the scripts/conversation.js
file:
When a user clicks the Submit button, the createConversation
function is called. In it, the contents of the form are collected and used in the body of a POST
request made to http://localhost:8000/api/conversations/
in the backend.
You will use axios
to make the request. If the request is successful, a conversation is
created and the user is added to it. The user will then be redirected to
the chat page where they can send messages in the conversation.
The Chat Page
On this page, a user will view a list of conversations they are part of and send messages to them. You can find the markup for pages/chat.html
here and the styling for styles/chat.css
here.
The scripts/chat.js
file starts out by defining a namespace twilioDemo
.
Add the initClient
function below. It is responsible for initializing the Twilio client and loading conversations.
When the page loads, initClient
fetches the user’s access token from the backend, then uses it to
initialise the client. Once the client is initialised, it’s used to
fetch all the conversations the user is subscribed to. After that, the
conversations are loaded onto the side-nav
. In case any error occurs, the user is sent to the error page.
The setConversion
function loads a single conversation. Copy and paste the code below in the file to add it:
When a user clicks on a particular conversation, setConversation
is called. This function receives the conversation SID and name and uses the SID
to fetch the conversation and its messages. The messages are then added
to the chat area. Lastly, a listener is added to watch for new messages
added to the conversation. These new messages are appended to the chat
area when they are received. In case any errors occur, an error message
is displayed.
Next, you’ll add the addMessagedToChatArea
function which loads conversation messages.
The function addMessagesToChatArea
adds messages of the current conversation to the chat area when it is
selected from the side nav. It is also called when new messages are
added to the current conversation. A loading message is usually
displayed as the messages are being fetched. Before the conversation
messages are added, this loading message is removed. Messages from the
current user are aligned to the right, while all other messages from
group participants are aligned to the left.
Add the sendMessage
function to send messages:
When the user sends a message, the sendMessage
function is called. It gets the message text from the text area and disables the submit button. Then using the currently selected conversation, the message is sent using its sendMessage
method. If successful, the text area is cleared and the submit button is re-enabled. If unsuccessful, an error message is displayed instead.
The showError
method displays an error message when it is called; hideError
hides it.
The logout
function logouts out the current user. It does this by making a request
to the backend which clears their session. The user is then redirected
to the conversation page, so they can create a new conversation if
they’d like.
Add the inviteFriend
function to send conversation invites:
To invite other people to participate in the conversation, the current user can send another person a link. This link is to the login page and contains the current conversation SID as a query parameter. When they click the invite button, the link is added to their clipboard. An alert is then displayed giving invite instructions.
The Login Page
On this page, a user logs in when they are invited to a conversation. You can find the markup for pages/login.html
at this link.
In scripts/login.js
, the login
function is responsible for logging in conversation invitees. Copy its code below and add it to the aforementioned file:
The login
function takes the conversation sid
query parameter from the URL and the username from the form. It then makes a POST
request to api/conversations/{sid}/participants/
on the backend app. The backend app adds the user to the conversation
and generates an access token for messaging. If successful, a session is
started in the backend for the user.
The user is then redirected to the chat page, but if the request returns an error, they are redirected to the error page. If there is no conversation sid
query parameter in the URL, the user is redirected to the conversation page.
Running the App
Before you can start the front-end app, make sure that the backend app is running. As mentioned earlier, you can start the backend app using this command on the terminal:
To serve the front-end app, run this command in a different terminal window:
This serves the app at http://localhost:3000. Once it’s running, head on over to http://localhost:3000/pages/conversation.html; set a name for your conversation and add your username, then create it. When you get to the chat page, click on the conversation
, then click the Invite button.
In a separate incognito window, paste the invite link and put a different username. Once you’re on the chat page in the incognito window, you can begin chatting with yourself. You can send messages back and forth between the user in the first window and the second user in the incognito window in the same conversation.
Conclusion
In this tutorial, you learned how to create a chat app using Twilio Conversations and Vanilla JS. You created a Node.js app that generates user access tokens, maintains a session for them, creates conversations, and adds users to them as participants. You also created a front-end app using HTML, CSS, and Vanilla JS. This app should allow users to create conversations, send messages, and invite other people to chat. It should get access tokens from the backend app and use them to perform these functions. I hope this tutorial gave you a better understanding of how Twilio Conversations works and how to use it for chat messaging.
No comments:
Post a Comment