Build an Appointment Scheduler using Node, Firebase, and Vonage
Introduction
In this tutorial, we are going to build an appointment scheduler web application using Node.js, Express, Firebase, and the Vonage Messages API. The GitHub repository for this project is also available, feel free to clone it here.
Set Up Firebase
To start, let’s create a new project from the Firebase console.
- Click on
add a new project
- Give your project a meaningful name, for instance
vonage appointment scheduler
- Check if you like the unique identifier id for your project (it is used in your Realtime Database URL, Firebase Hosting subdomains, and more. It cannot be changed after project creation)
- Click on the button to continue
- Select if you want to enable analytics. We won’t in this tutorial
- Click on the button to create the project
- Wait for the project to be created
- Once the project is ready, click to continue. You will be taken to your project’s console view
- Set the Billing type by clicking on the gear icon, followed by Usage and Billing, then on the Details & Settings tab and modify the plan to use Blaze. This pay-as-you-go plan is required when using a third-party API
Install Firebase Tools CLI
From your terminal, install the Firebase tools with NPM if you don’t already have them by typing: npm install -g firebase-tools
. Next, type firebase login. This will open a window in your browser which will either authenticate you automatically (if you're already logged in) or ask you for your credentials. Once that's complete you now have the Firebase CLI installed.
Create and Set Up a RealTime Database
Now it’s time for us to create the NoSQL database instance that will hold the appointment slots’ information. Our app will include a view where a user will be able to make or cancel appointments. As the person interacting with the view picks an appointment date and time, that slot will be added or removed from the Firebase RealTime Database.
- Click on “Create Database”
- Select the Realtime Database location where your data will be stored and click on
next
- Select if you will use the database in locked or test mode. For this example, I am using the test mode
- Click
enable
Import the Database JSON File
Let’s import an example database which already contains some allocated slots, and from which you’ll be able to add and remove future slots. You can create a file called myAppointments.json
containing the JSON in the snippet below, and then import this file from the console.
Add the Database Rules
The Firebase Realtime Database Rules determine who can access your database, how your indexes are built, and how your data is structured.
- From the Firebase console on the Realtime database view, you can see “Rules”, click on that tab. You’ll be taken to a screen that will allow you to edit your rules
- Copy and paste the rules from the below code snippet to your console in order to set the
myAppointments
collection to be indexed by thedate
field. - Click on
Publish
Create the Project Structure
By the end of this tutorial, this is roughly how your project structure will look like. In the following steps, we will create the files that will build up the content, appearance, functionalities, and handle the services we will use.
Setup
- Create the project folder and
cd
into it:mkdir appointment-scheduler && cd appointment-scheduler
- Initialize NPM:
npm init
. This command prompts you to add information about the project - Install the dependencies:
npm install @vonage/server-sdk dotenv uuid express firebase-admin firebase-functions
- Type
firebase init
. Since we already created a project in the dashboard, you can selectUse an existing project
which will prompt you to choose the desired project. You can see my example with my project idvonage-appointment-scheduler
below. I also chose to use theRealtime Database
feature
Create the HTML Content
Did you know that the HTML input element has many type options for date and time selection? For instance, we have: date
, datetime-local
, time
. For this tutorial, we will use <input type="datetime-local">
. This approach is perhaps not as robust as using date-time library, as there can be some inconsistencies, but it works for the purpose of this tutorial. The user will be able to book slots every 5 minutes ending in 0 or 5 for instance 18:00 is bookable but 18:01 is not.
Add CSS Styling
For this demonstration web app, we’ll add some styling to center the contents on the page, and also display a red ✖ in case the input is invalid and a ✓ in case it is valid.
- Create the
public/styles.css
file - Paste in the below CSS code
- The
FIREBASE_DATABASE_URL
can be found on the Firebase console - The
VONAGE_API_KEY
and theVONAGE_API_SECRET
can be found in the Vonage Dashboard - The
VONAGE_FROM_NUMBER
contains the number, name, or brand that will appear as the sender of the message - The
VONAGE_TO_NUMBER
is the number that will receive the SMS messages
Create the JavaScript file `server.js`
We will create the server.js
to tell Express how to handle the requests posted by the UI. I'll show you step by step how we will build it. You can find the complete server file here.
Our web app will use express and it will read the static files we previously created from the public
folder.
Add the Service Account
A Firebase service account can be used to authenticate various Firebase features, for our project we will use the Firebase Admin SDK to access our Database URL.
- From the Firebase Console click on the gear and select the Service Account tab
- Click on the button to
generate key
- Add the generated file to the root of your project and rename it to
serviceAccountKey.json
- Copy and paste the Admin SDK configuration snippet to your project, as you can see in the following step of this tutorial, to initialize Firebase. We are using
${process.env.FIREBASE_DATABASE_URL
to read the URL from the.env
file but it's the same Database URL found on the Firebase Admin SDK configuration.
Initialize Firebase
We use initializeApp
to create and initialize a Firebase app instance that will use the /myAppointments
Firebase database instance we have previously created and populated from the Firebase Console.
Initialize the Vonage API object
We create the instance of the Vonage client class, initializing it with the Vonage API Key and Secret that you have previously added to your .env
file.
Create the getDateTime() Function
The HTML input type datetime-local
is formatted as YYYY-MM-DDThh:mm. So we will write a function to separate the date from the hour by splitting it on the character T
. For instance in the example 2018-06-12T19:30
we'd have 2018-06-12
for the date and 19:30
for the hour.
Create the `/appointment`
endpoint
It’s time to create the /appointment
endpoint to handle the POST requests for creating an appointment. This endpoint will check if the slot is available, it will add the slot to the Firebase database, and finally, it will send an SMS confirmation back to the user's phone using the Vonage Messages API.
You may have noticed that much of the functionality within the request handler has not yet been implemented, so let’s now expand on the stubs for the required functionalities.
Check Slot Availability
This function validates if a slot is available by checking if the slot already exists in the database. We are querying ref.orderByChild('date')
. Queries are allowed to order one key at a time. We have previously defined our index via the .indexOn
on the Firebase Rules for better performance. And then we make use .once('value')
to listen for exactly one event of the value, and then it stops listening.
Add the Slot to the Database
The following function addToDatabase()
adds the slot and a code to the Firebase database. This code is required to cancel the appointment.
Send an SMS with the Appointment Information
Finally, once the slot is reserved, an SMS confirmation is sent back to the user with the message Meeting booked at ${time} on date: ${date}. Please save this code: ${code} in case you'd like to cancel your appointment.
as you can see in the function sendSMStoUser()
.
Finalize the Business Logic
The piece of code below is responsible to call the previously created helper functions. If the slot is available, the user will have their slot added to the database and have the SMS sent back to them. Otherwise, they will be requested to choose a different time slot.
Cancel the Appointment `/cancelAppointment`
Let’s create the /cancelAppointment
endpoint handling the POST requests for canceling an appointment from the database by using a code provided by the user that they received upon scheduling their appointment.
Listen to the Port
Finally, the app will be listening on the specified port, if run locally this will be accessible on https://localhost:${port}
. In this URL you can interact with the UI of this demo application and check the slots being added/ removed on the Firebase console web page.
Test it Out
- Install all the dependencies
npm install
- Run the NPM command to execute the project
npm run start
- Navigate to
http://localhost:3000
- Add and remove appointment slots and see them being added and removed from the Firebase Realtime Database
Conclusion and Next Steps
Today you saw how to build an appointment scheduler demo web app. Now you can go ahead and add fancier styling and other functionalities. You can take what you learned here to create many appointment schedulers may it be for a gym or for a vaccination slot — let the creativity flow!