Frequently Asked Questions
You can schedule SMS messages by sending a POST request to the /sms/2/bulks endpoint of your Fastify application. This request should include the recipient's phone number, the message text, the desired send time (in ISO 8601 format), and optionally a sender ID. The application will then interact with the Infobip API to schedule the message.
Prisma acts as an Object-Relational Mapper (ORM), simplifying database interactions. It is used to define the database schema, manage migrations, and execute type-safe queries. In this project, Prisma interacts with an SQLite database to store metadata about scheduled SMS jobs, but it's compatible with other databases like PostgreSQL and MySQL as well.
Fastify is a high-performance Node.js web framework known for its speed, extensibility, and developer-friendly features. It offers built-in validation, logging, and a plugin-based architecture, making it a suitable choice for building robust and efficient backend services like this SMS scheduler.
A unique bulk ID, generated using the uuid
library, should be created client-side before making the API call to Infobip to schedule a message. This bulkId
helps to track and manage the scheduled message within your system and correlate it with Infobip's responses.
Create a .env
file in the project's root directory. Store sensitive information like the Infobip API key and base URL, database URL, and port number. Use the @fastify/env
module along with a schema defined in src/config/environment.js
for secure loading and validation.
You can retrieve the status of a scheduled message by sending a GET request to the /sms/2/bulks/status
endpoint with the bulkId
as a query parameter. The response from the Infobip API, routed through your Fastify app, will indicate whether the message is pending, canceled, or sent.
The ScheduledSmsJob
model, managed via Prisma, stores key information about scheduled SMS jobs: a unique internal id
, the Infobip bulkId
, current status
, scheduledAt
timestamp, recipient phone number, message content, and timestamps for creation and updates.
While optional, Sentry integration is recommended for production applications. Include your Sentry DSN in the .env
file and configure Sentry within your Fastify application to automatically capture and report errors, enhancing monitoring and debugging capabilities.
The system follows a client-server architecture where a client (e.g., UI or Postman) interacts with a Fastify backend application. The backend communicates with an Infobip API for sending and scheduling SMS messages and a database (SQLite) for storing scheduling metadata.
Yes, you can reschedule SMS messages through a PUT request to the /sms/2/bulks
endpoint. Supply the bulkId
and the new desired send time (sendAt
in ISO 8601 format) in the request body.
The databaseService.js
file contains functions for interacting with the database. These functions, built upon Prisma, allow you to save job details, retrieve jobs by their bulkId
, and update job status information.
You need Node.js (v18 or later is recommended), npm or yarn, an active Infobip account (signup is available online), basic understanding of JavaScript and RESTful APIs, a code editor, and optionally, Docker and Postman or cURL for testing.
Axios is a promise-based HTTP client used for making API requests to the Infobip platform from your Node.js application. It simplifies the process of sending HTTP requests and handling responses within the project.
Pino is the high-performance logger employed within this project. It automatically formats logs in JSON for improved analysis and debugging. For human-readable logs during development, Pino Pretty can be used through npm scripts.
Building Production-Ready SMS Scheduling & Reminders with Fastify and Infobip
This guide provides a complete walkthrough for building a robust SMS scheduling and reminder system using the Fastify web framework for Node.js and the Infobip communications platform. We will cover everything from project setup to deployment, focusing on production-readiness, best practices, and real-world considerations.
By the end of this tutorial, you will have a functional application capable of:
This system solves the common business need for automated, timed communication like appointment reminders, payment due date notifications, event follow-ups, and abandoned cart recovery messages, helping to reduce no-shows, improve engagement, and save manual effort.
Project Overview and Goals
We aim to build a backend service using Fastify that exposes a RESTful API for managing scheduled SMS messages via Infobip.
Technologies Used:
.env
file intoprocess.env
.System Architecture:
InfobipService
andDatabaseService
.bulkId
returned by Infobip) and potentially links it to internal application data.Prerequisites:
curl
for testing API endpoints.Final Outcome:
A deployable Fastify application with API endpoints to fully manage the lifecycle of scheduled SMS messages via Infobip, complete with logging, error handling, database persistence, and basic security considerations.
1. Setting up the Project
Let's initialize our Fastify project and set up the basic structure and dependencies.
Step 1: Initialize Node.js Project
Open your terminal and create a new project directory:
Step 2: Configure
package.json
for ES ModulesSince we'll be using
import
/export
syntax throughout the project, add"type": "module"
to yourpackage.json
:.js
files in this project as ES Modules, allowing the use ofimport
andexport
statements natively.Step 3: Install Fastify and Core Dependencies
fastify
: The core framework.@fastify/env
: For loading and validating environment variables.axios
: For making HTTP requests to the Infobip API.prisma
,@prisma/client
: The Prisma CLI and runtime client.dotenv
: Loads.env
file (though@fastify/env
handles this too,dotenv
can be useful for scripts like seeding).uuid
: To generate unique bulk IDs for Infobip requests.Step 4: Install Development Dependencies
nodemon
: Automatically restarts the server during development on file changes.concurrently
: Runs multiple commands concurrently (useful for watching files and running the server).pino-pretty
: For human-readable logs during development (used only by thedev
script).typescript
,ts-node
,@types/node
: Although we write JS, Prisma works best with TS tooling installed for generation.jest
,@types/jest
: Testing framework (as discussed in Section 13).Step 5: Configure
package.json
ScriptsAdd the following scripts to your
package.json
:test
script includesnode --experimental-vm-modules
which is often required for Jest to work correctly with ES Modules.Step 6: Set up Project Structure
Create the following directories and files:
Step 7: Create
.gitignore
Create a
.gitignore
file in the root directory. Migration SQL files should be committed.Step 8: Create
.env.template
and.env
Create
.env.template
with the required variables:Now, create a
.env
file by copying.env.template
and fill in your actual Infobip Base URL and API Key. Never commit your.env
file to version control.Step 9: Configure Environment Loading (
src/config/environment.js
)This file defines the schema for
@fastify/env
to validate and load environment variables.@fastify/env
provides automatic validation and type coercion for environment variables, preventing runtime errors due to misconfiguration. It centralizes environment management.Step 10: Configure Prisma (
prisma/schema.prisma
)Define the database schema. We'll create a simple table to track our scheduled jobs.
bulkId
to an internal record, track its intendedscheduledAt
time,status
(which we'll manage based on Infobip responses), and other relevant details like the recipient and message text for easier debugging or application logic.@unique
onbulkId
ensures we don't have duplicate entries for the same Infobip job. Added indexes onstatus
andscheduledAt
for potential performance improvements.Step 11: Initialize Prisma Database
Run the following command to create the initial database file and migration:
This will:
prisma/migrations
directory containing the SQL migration file.dev.db
SQLite file (or prompt for database creation if using another provider).@prisma/client
).You can inspect the database using Prisma Studio:
2. Implementing Core Functionality (Services)
Now, let's create the services that encapsulate the logic for interacting with Infobip and our database.
Step 1: Implement Database Service (
src/services/databaseService.js
)This service will handle all interactions with our
ScheduledSmsJob
table using Prisma Client.Step 2: Implement Infobip Service (
src/services/infobipService.js
)This service handles all communication with the Infobip API.
axios
instance with interceptors.bulkId
client-side usinguuid
.initialize
function for simplicity, with notes on DI being a better pattern for larger apps.3. Building the API Layer (Routes and Controllers)
Let's expose the service functionality through Fastify routes and controllers.
Step 1: Create SMS Controller (
src/controllers/smsController.js
)Handles requests, validates input, calls services, and formats responses.