This guide provides a step-by-step walkthrough for building a Node.js application using the Fastify framework to send SMS messages via the Plivo API. We will cover project setup, core implementation, error handling, security considerations, and deployment basics.
By the end of this guide, you will have a functional Fastify API endpoint capable of accepting requests and triggering SMS messages through Plivo, along with the foundational knowledge to expand upon it.
Project Overview and Goals
Goal: To create a simple, robust, and scalable API endpoint using Fastify that sends SMS messages via the Plivo communication platform.
Problem Solved: Provides a backend service that abstracts the Plivo SMS sending functionality, enabling other services or frontend applications to send SMS messages easily through a standard REST API call without needing direct access to Plivo credentials or SDKs.
Technologies:
- Node.js: A JavaScript runtime environment enabling server-side execution.
- Fastify: A high-performance, low-overhead web framework for Node.js, chosen for its speed, extensibility, and developer-friendly features like built-in validation.
- Plivo: A cloud communications platform providing APIs for SMS, voice, and more. We'll use their Node.js SDK.
- dotenv: A zero-dependency module to load environment variables from a
.env
file intoprocess.env
, crucial for managing sensitive credentials securely.
System Architecture:
+-------------+ +---------------------+ +--------------+ +-----------------+
| Client (e.g.,| ----> | Fastify API Server | ----> | Plivo Node.js| ----> | Plivo API |
| Postman/App)| | (Node.js) | | SDK | | (Sends SMS) |
+-------------+ +---------------------+ +--------------+ +-----------------+
| | Send Request (POST) | Uses Credentials | Delivers Message
| | Validate Request | Constructs API Call |
| | Call Plivo SDK | Handles Response |
|<--------------------| Return Response |<----------------------| Returns Status
| | (Success/Error) | (e.g._ Message UUID) |
+ +---------------------------------+-----------------------+
Prerequisites:
- Node.js and npm (or yarn): Ensure you have a recent LTS version of Node.js installed. You can download it from nodejs.org. npm is included with Node.js.
- Plivo Account: Sign up for a Plivo account at plivo.com.
- Plivo Credentials: Obtain your Auth ID and Auth Token from the Plivo console dashboard.
- Plivo Phone Number: Acquire an SMS-enabled Plivo phone number from the
`Phone Numbers`
section of the Plivo console. This will be your sender number (src
). Note specific regulations for sender IDs in different countries; a Plivo number is generally required for sending to the US and Canada. - Verified Destination Number (Trial Account): If using a Plivo trial account_ you must verify any destination phone numbers in the Plivo console under
`Phone Numbers`
>`Sandbox Numbers`
before you can send messages to them.
Final Outcome: A running Fastify server with a single API endpoint (POST /sms/send
) that accepts a destination number and message text, sends the SMS via Plivo, and returns a confirmation or error.
1. Setting up the Project
Let's initialize our Node.js project and install the necessary dependencies.
-
Create Project Directory: Open your terminal and create a new directory for your project, then navigate into it.
mkdir fastify-plivo-sms cd fastify-plivo-sms
-
Initialize Node.js Project: Initialize the project using npm, creating a
package.json
file. The-y
flag accepts default settings.npm init -y
-
Install Dependencies: Install Fastify, the Plivo Node.js SDK, and
dotenv
.npm install fastify plivo dotenv
-
Set Up Project Structure: Create a basic structure for organization.
mkdir src mkdir src/routes mkdir src/config touch src/server.js touch src/routes/sms.js touch src/config/plivo.js touch .env touch .gitignore
src/server.js
: Main application entry point, Fastify server setup.src/routes/sms.js
: Defines the routes related to SMS functionality.src/config/plivo.js
: Initializes and configures the Plivo client..env
: Stores sensitive credentials (Plivo Auth ID, Token, Number). Never commit this file to version control..gitignore
: Specifies intentionally untracked files that Git should ignore.
-
Configure
.gitignore
: Addnode_modules
and.env
to your.gitignore
file to prevent them from being checked into Git..gitignore
node_modules/ .env *.log
-
Configure Environment Variables (
.env
): Open the.env
file and add your Plivo credentials and phone number. Replace the placeholder values with your actual credentials found in the Plivo console..env
# Plivo Credentials - Found on your Plivo Console Dashboard PLIVO_AUTH_ID=YOUR_PLIVO_AUTH_ID PLIVO_AUTH_TOKEN=YOUR_PLIVO_AUTH_TOKEN # Plivo Phone Number - An SMS-enabled number from your Plivo account PLIVO_SENDER_NUMBER=+1XXXXXXXXXX # Use E.164 format (e.g., +12025551234)
PLIVO_AUTH_ID
: Your Plivo account identifier.PLIVO_AUTH_TOKEN
: Your Plivo account secret token.PLIVO_SENDER_NUMBER
: The SMS-enabled Plivo phone number you purchased, in E.164 format.
2. Implementing Core Functionality (Sending SMS)
Now, let's write the code to initialize the Plivo client and set up the Fastify server.
-
Configure Plivo Client: Set up the Plivo client instance using the environment variables.
src/config/plivo.js
'use strict'; const plivo = require('plivo'); require('dotenv').config(); // Load .env variables // Ensure essential environment variables are set if (!process.env.PLIVO_AUTH_ID || !process.env.PLIVO_AUTH_TOKEN) { console.error('Error: Plivo Auth ID or Auth Token not found in environment variables.'); console.error('Please check your .env file or environment configuration.'); process.exit(1); // Exit if critical configuration is missing } // Initialize Plivo client const client = new plivo.Client( process.env.PLIVO_AUTH_ID, process.env.PLIVO_AUTH_TOKEN ); module.exports = client; // Export the configured client instance
- Why
dotenv
here? We load environment variables early to ensure the Plivo client can be initialized correctly. - Why the check? Explicitly checking for credentials prevents the application from starting in an invalid state and provides clear error messages.
- Why
-
Create the SMS Sending Route: Define the Fastify route that will handle the SMS sending request.
src/routes/sms.js
'use strict'; const plivoClient = require('../config/plivo'); // Import the configured Plivo client require('dotenv').config(); // Ensure env vars are loaded // Define the schema for request validation // Ensures 'to' and 'text' are provided and are strings const sendSmsSchema = { body: { type: 'object', required: ['to', 'text'], properties: { to: { type: 'string', description: 'Destination phone number in E.164 format (e.g., +15551234567)' }, text: { type: 'string', description: 'The content of the SMS message' }, }, }, response: { 200: { type: 'object', properties: { message: { type: 'string' }, message_uuid: { type: 'array', items: { type: 'string' } }, // Plivo API returns message_uuid as an array }, }, // Define other response schemas (e.g., 400, 500) as needed }, }; async function smsRoutes(fastify, options) { // Ensure the sender number is available const senderNumber = process.env.PLIVO_SENDER_NUMBER; if (!senderNumber) { fastify.log.error('PLIVO_SENDER_NUMBER is not set in environment variables.'); // Optionally, throw an error during setup if this is critical // throw new Error('PLIVO_SENDER_NUMBER is required.'); } fastify.post('/sms/send', { schema: sendSmsSchema }, async (request, reply) => { // Check again in handler in case it wasn't critical at setup if (!senderNumber) { reply.code(500).send({ error: 'Server configuration error: Sender number not set.' }); return; } const { to, text } = request.body; // Basic E.164 format check (can be improved with a library) if (!/^\+[1-9]\d{1,14}$/.test(to)) { reply.code(400).send({ error: 'Invalid destination phone number format. Use E.164 (e.g., +15551234567).' }); return; } try { fastify.log.info(`Attempting to send SMS to ${to} from ${senderNumber}`); const response = await plivoClient.messages.create( senderNumber, // Source number (from .env) to, // Destination number (from request body) text // Message text (from request body) ); fastify.log.info(`SMS sent successfully. Message UUID: ${response.messageUuid}`); // Send success response back to the client reply.code(200).send({ message: 'SMS sent successfully!', message_uuid: response.messageUuid, // Plivo API returns this as an array according to schema comment }); } catch (error) { fastify.log.error(`Error sending SMS via Plivo: ${error.message}`); fastify.log.error(error.stack); // Log the full stack trace for debugging // Determine appropriate error code based on Plivo error or internal issue // This is a basic example; more sophisticated mapping might be needed let statusCode = 500; let errorMessage = 'Failed to send SMS due to an internal server error.'; if (error.statusCode) { // Use Plivo's status code if available (e.g., 400 for bad request) statusCode = error.statusCode >= 500 ? 502 : error.statusCode; // Treat Plivo 5xx as 502 Bad Gateway errorMessage = `Failed to send SMS. Plivo API error: ${error.message}`; } reply.code(statusCode).send({ error: errorMessage, details: error.message }); } }); } module.exports = smsRoutes;
- Why Fastify Schema? Fastify's built-in schema validation automatically validates incoming request bodies and serializes responses, reducing boilerplate code and improving security/reliability.
- Why
async/await
? Simplifies handling asynchronous operations like the Plivo API call. - Why E.164 Check? Plivo requires numbers in E.164 format. Basic validation catches common errors early. A dedicated library like
libphonenumber-js
offers more robust validation. - Why
try...catch
? Essential for handling potential errors during the API call to Plivo (network issues, invalid credentials, API errors, etc.).
-
Set Up the Fastify Server: Configure and start the Fastify server, registering the SMS routes.
src/server.js
'use strict'; require('dotenv').config(); // Load environment variables early // Instantiate Fastify with basic logging enabled const fastify = require('fastify')({ logger: true, // Enable Fastify's built-in Pino logger }); // Register the SMS routes // The prefix option namespaces all routes defined in smsRoutes under '/api' fastify.register(require('./routes/sms'), { prefix: '/api' }); // Basic health check route fastify.get('/health', async (request, reply) => { return { status: 'ok', timestamp: new Date().toISOString() }; }); // Define the start function const start = async () => { try { const port = process.env.PORT || 3000; await fastify.listen({ port: port, host: '0.0.0.0' }); // Listen on all available network interfaces fastify.log.info(`Server listening on port ${port}`); } catch (err) { fastify.log.error(err); process.exit(1); } }; // Start the server start();
- Why
logger: true
? Enables request/response logging and allows usingfastify.log
for custom logs. - Why
register
withprefix
? Organizes API routes under a common base path (e.g.,/api/sms/send
). - Why
0.0.0.0
? Makes the server accessible from outside its container/machine in development or production (localhost/127.0.0.1 only allows local connections). - Why Health Check? A simple
/health
endpoint is standard practice for monitoring services and load balancers.
- Why
-
Add Start Script to
package.json
: Add a script to easily start your server.package.json (additions)
{ // ... other package.json content ... ""scripts"": { ""start"": ""node src/server.js"", ""test"": ""echo \""Error: no test specified\"" && exit 1"" }, // ... other package.json content ... }
3. Building a Complete API Layer
Our core API endpoint (POST /api/sms/send
) is already set up. Let's document and demonstrate how to test it.
API Endpoint Documentation:
- Method:
POST
- Path:
/api/sms/send
- Body (JSON):
to
(string, required): The destination phone number in E.164 format (e.g.,+12025551234
).text
(string, required): The content of the SMS message. Max length depends on encoding (GSM-7 or UCS-2).
- Success Response (200 OK):
message
(string): Confirmation message (e.g.,"SMS sent successfully!"
).message_uuid
(array of strings): An array containing the unique identifier assigned by Plivo to the message request.- Example:
{ "message": "SMS sent successfully!", "message_uuid": ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"] }
- Error Responses:
- 400 Bad Request: Invalid input (missing fields, invalid phone number format).
{ "error": "Invalid destination phone number format. Use E.164 (e.g., +15551234567)." }
{ "statusCode": 400, "code": "FST_ERR_VALIDATION", "error": "Bad Request", "message": "body should have required property 'to'" }
- 500 Internal Server Error / 502 Bad Gateway: Server configuration issue or error communicating with Plivo.
{ "error": "Failed to send SMS due to an internal server error.", "details": "Specific error message from Plivo or internal logic" }
- 400 Bad Request: Invalid input (missing fields, invalid phone number format).
Testing with curl
:
-
Start the Server:
npm start
You should see output indicating the server is listening on port 3000 (or your configured
PORT
). -
Send a Request: Open another terminal window and run the following
curl
command. Replace+1DESTINATIONNUMBER
with a verified phone number (if using a trial account) in E.164 format.curl -X POST http://localhost:3000/api/sms/send \ -H "Content-Type: application/json" \ -d '{ "to": "+1DESTINATIONNUMBER", "text": "Hello from Fastify and Plivo!" }'
-
Check Response: You should receive a JSON response like the success example above, and the destination phone should receive the SMS shortly after. Check your server logs (
npm start
terminal) for detailed request/response information and potential errors.
4. Integrating with Necessary Third-Party Services (Plivo)
We've already integrated Plivo, but let's reiterate the key configuration steps.
-
Obtain Credentials:
- Navigate to your Plivo Console: https://console.plivo.com/
- Auth ID & Auth Token: These are prominently displayed on the main dashboard page after logging in.
- Plivo Phone Number: Go to
`Phone Numbers`
>`Your Numbers`
. If you don't have one, click`Buy Number`
, search for SMS-enabled numbers in your desired region, and purchase one. Copy the number in E.164 format. - (Trial Account) Sandbox Numbers: Go to
`Phone Numbers`
>`Sandbox Numbers`
to add and verify destination numbers you want to send messages to during trial.
-
Secure Credential Storage:
- Place your Auth ID, Auth Token, and Plivo Sender Number into the
.env
file in the project root. - Crucially: Ensure
.env
is listed in your.gitignore
file to prevent accidentally committing secrets to version control.
- Place your Auth ID, Auth Token, and Plivo Sender Number into the
-
Environment Variables Explained:
.env
# Plivo Credentials - Found on your Plivo Console Dashboard PLIVO_AUTH_ID=YOUR_PLIVO_AUTH_ID # Purpose: Identifies your account to Plivo. Format: String. How to get: Plivo Dashboard. PLIVO_AUTH_TOKEN=YOUR_PLIVO_AUTH_TOKEN # Purpose: Authenticates your API requests. Format: String (Secret). How to get: Plivo Dashboard. # Plivo Phone Number - An SMS-enabled number from your Plivo account PLIVO_SENDER_NUMBER=+1XXXXXXXXXX # Purpose: The 'From' number for outgoing SMS. Format: E.164 String (e.g., +12025551234). How to get: Plivo Console > Phone Numbers > Your Numbers.
-
Fallback Mechanisms (Conceptual): For this basic guide, we don't implement automatic fallback. In a production system, if Plivo experiences downtime, you might consider:
- Retry Logic: Implement retries with exponential backoff (covered briefly in Error Handling).
- Circuit Breaker Pattern: Prevent repeated calls to a failing service.
- Alternative Provider: Integrate a secondary SMS provider and switch if Plivo fails (adds significant complexity).
5. Implementing Error Handling, Logging, and Retry Mechanisms
We've incorporated basic error handling and logging.
- Error Handling Strategy: Use
try...catch
blocks around external API calls (Plivo). Catch errors, log them with details (fastify.log.error
), and return appropriate HTTP status codes (4xx for client errors, 5xx for server/Plivo errors) and informative JSON error messages to the client. Map Plivo errors to relevant HTTP statuses where possible. - Logging: Fastify's built-in Pino logger (
logger: true
) provides efficient JSON-based logging for requests, responses, and errors. Custom logs (fastify.log.info
,fastify.log.error
) add context. In production, logs should be collected and forwarded to a centralized logging system (e.g., Datadog, ELK stack, Splunk). - Retry Mechanisms (Conceptual):
The Plivo Node.js SDK does not have built-in automatic retries for sending messages upon failure. Implementing robust retries requires careful consideration:
- Identify Retryable Errors: Only retry on transient errors (e.g., network timeouts, Plivo 5xx errors), not permanent ones (e.g., invalid credentials, invalid number format - 4xx errors).
- Exponential Backoff: Increase the delay between retries exponentially (e.g., 1s, 2s, 4s, 8s) to avoid overwhelming the Plivo API during intermittent issues.
- Max Retries: Limit the number of retries to prevent indefinite loops.
- Idempotency: Ensure retrying a request doesn't result in duplicate messages (Plivo handles some level of idempotency, but designing your system carefully is still important).
- Implementation: You could use libraries like
async-retry
or build custom logic within yourcatch
block. For this guide's scope, we only log the error.
Testing Error Scenarios:
- Invalid Input: Send a request missing the
to
ortext
field, or with an invalid phone number format (e.g.,12345
). Expect a 400 error from Fastify validation or your custom check. - Invalid Credentials: Temporarily change
PLIVO_AUTH_ID
orPLIVO_AUTH_TOKEN
in.env
and restart the server. Send a valid request. Expect a 401 Unauthorized error (or similar) from the Plivo API, which your error handler should catch and return as a 4xx or 5xx error. - Invalid Sender Number: Use a number not associated with your Plivo account in
PLIVO_SENDER_NUMBER
. Expect an error from Plivo. - Trial Account Limit: Send to an unverified number using a trial account. Expect a specific Plivo error related to sandbox restrictions.
6. Creating a Database Schema and Data Layer
Not Applicable: This specific microservice focuses solely on the stateless action of sending an SMS via an external API. It does not require its own database to store state related to the messages (Plivo handles the message persistence and status tracking).
If you needed to track requests, log message attempts internally, or associate messages with users in your system, you would add a database (e.g., PostgreSQL, MongoDB) and a data access layer (e.g., using an ORM like Prisma or Sequelize, or a MongoDB driver).
7. Adding Security Features
-
Input Validation: Implemented using Fastify's schema validation (
sendSmsSchema
). This prevents malformed requests and basic injection attempts in theto
andtext
fields. Sanitize or strictly validate any user input that might be used in logs or other contexts. -
Secure Credential Handling: Using
.env
and.gitignore
prevents exposure of Plivo API keys. In production, use environment variables provided by the deployment platform or a dedicated secrets management system (e.g., HashiCorp Vault, AWS Secrets Manager). -
Rate Limiting: Protect against brute-force attacks or abuse by limiting the number of requests per IP address or user. Use the
fastify-rate-limit
plugin.- Install:
npm install fastify-rate-limit
- Register in
server.js
:// src/server.js // ... other requires ... const rateLimit = require('fastify-rate-limit'); // ... fastify instantiation ... // Register rate limiting plugin BEFORE your routes fastify.register(rateLimit, { max: 100, // Max requests per window timeWindow: '1 minute' // Time window }); // Register the SMS routes AFTER rate limiting fastify.register(require('./routes/sms'), { prefix: '/api' }); // ... rest of server.js ...
- Install:
-
Security Headers: Use a plugin like
@fastify/helmet
to set various HTTP headers (likeX-Frame-Options
,Strict-Transport-Security
, etc.) to protect against common web vulnerabilities.- Install:
npm install @fastify/helmet
- Register in
server.js
:// src/server.js // ... other requires ... const helmet = require('@fastify/helmet'); // ... fastify instantiation ... // Register helmet BEFORE routes fastify.register(helmet); // ... register rate limit, routes, etc. ...
- Install:
-
HTTPS: Always run your API over HTTPS in production using a reverse proxy like Nginx or your cloud provider's load balancer to handle SSL termination.
8. Handling Special Cases Relevant to the Domain
- E.164 Format: Strictly enforce the E.164 format for phone numbers (
+
followed by country code and number, no spaces or dashes) as required by Plivo. - Character Encoding (GSM vs. Unicode):
- Standard SMS uses the GSM-7 character set (160 characters per segment).
- Using characters outside this set (like many emojis or non-Latin characters) automatically switches the message to UCS-2 encoding, which limits segments to 70 characters.
- Plivo handles this automatically, but be aware that messages containing even one Unicode character will be shorter per segment and may cost more if they split into more parts.
- Message Concatenation (Multipart SMS):
- If a message exceeds the character limit for a single segment (160 for GSM, 70 for Unicode), Plivo automatically splits it into multiple linked segments (concatenated SMS).
- Each segment consumes SMS credits. A long message can result in multiple billed messages. The Plivo SDK and API handle the splitting and concatenation headers.
- Sender ID Restrictions:
- US/Canada: Generally require using a Plivo long code or Toll-Free number as the sender ID (
src
). Alphanumeric sender IDs are often blocked. - Other Countries: Rules vary. Some allow alphanumeric sender IDs (e.g.,
`MyCompany`
), which may need pre-registration. Check Plivo's documentation for country-specific regulations. Our code uses thePLIVO_SENDER_NUMBER
which works for US/Canada.
- US/Canada: Generally require using a Plivo long code or Toll-Free number as the sender ID (
- Rate Limits (Plivo): Plivo enforces API rate limits (e.g., messages per second per number). Sending too rapidly can result in errors. Implement delays or throttling in your application if sending bulk messages.
9. Implementing Performance Optimizations
- Fastify Choice: Using Fastify already provides a high-performance foundation due to its low overhead and efficient request lifecycle.
- Asynchronous Operations: Using
async/await
ensures Node.js's event loop is not blocked during the Plivo API call. - Logging: Pino (Fastify's default logger) is designed for high performance. Avoid excessive or synchronous logging in hot paths.
- Caching: Not directly applicable for the action of sending a unique SMS. Caching might be relevant if you frequently look up user data before sending, but not for the Plivo call itself.
- Load Testing: Use tools like
k6
,autocannon
, orwrk
to simulate traffic and identify bottlenecks under load. Monitor CPU, memory, and event loop lag during tests.# Example using autocannon (install with: npm install -g autocannon) autocannon -m POST -H "Content-Type=application/json" -b '{"to":"+1DESTINATIONNUMBER", "text":"Load test message"}' http://localhost:3000/api/sms/send
- Profiling: Use Node.js built-in profiler or tools like
0x
to analyze CPU usage and identify performance bottlenecks within your code.
10. Adding Monitoring, Observability, and Analytics
- Health Checks: The
/health
endpoint provides a basic mechanism for load balancers or monitoring systems (like UptimeRobot, Nagios, Datadog Synthetics) to check if the service is running. - Performance Metrics: Instrument your application to track key metrics:
- Request latency (Fastify can help).
- Request rate (requests per second).
- Error rates (specifically Plivo API errors vs. internal errors).
- Node.js process metrics (CPU, memory, event loop lag).
- Use libraries like
prom-client
for Prometheus integration or platform-specific agents (Datadog, New Relic).
- Error Tracking: Integrate with services like Sentry, Bugsnag, or Datadog APM to capture, aggregate, and alert on application errors in real-time, providing more context than just logs.
- Structured Logging: The JSON logs produced by Pino are easily parseable by log aggregation platforms (ELK, Splunk, Datadog Logs, etc.), enabling searching, filtering, and dashboard creation based on log data (e.g., tracking SMS send rates, error types).
- Dashboards: Create dashboards in your monitoring/logging tool to visualize key metrics: SMS send volume over time, error rates, API latency percentiles, health check status.
- Alerting: Configure alerts based on critical thresholds:
- High error rate (e.g., >5% Plivo API errors).
- Increased latency (e.g., p95 latency > 1s).
- Health check failures.
- Server resource exhaustion (high CPU/memory).
11. Troubleshooting and Caveats
- Common Errors & Solutions:
Error: Plivo Auth ID or Auth Token not found...
: EnsurePLIVO_AUTH_ID
andPLIVO_AUTH_TOKEN
are correctly set in your.env
file and the file is being loaded (require('dotenv').config();
).401 Unauthorized
(from Plivo): Incorrect Auth ID or Auth Token. Double-check values in.env
against the Plivo console.Invalid 'src' parameter
/Invalid 'dst' parameter
(from Plivo): Phone numbers are likely not in E.164 format or are otherwise invalid. Ensure numbers start with+
and country code. CheckPLIVO_SENDER_NUMBER
in.env
and theto
number in the request.Message Sending disallowed to Sandbox Number
(from Plivo): You are using a trial account and trying to send to a number not verified in`Sandbox Numbers`
on the Plivo console. Add and verify the destination number.Message Sender 'src' number not owned by you or is invalid
(from Plivo): ThePLIVO_SENDER_NUMBER
in.env
is incorrect or not associated with your Plivo account.- Fastify
FST_ERR_VALIDATION
(400 Bad Request): The request body doesn't match the schema defined insrc/routes/sms.js
(e.g., missingto
ortext
, or they are not strings). ENOTFOUND
/ETIMEDOUT
: Network issues connecting from your server to the Plivo API. Check server connectivity, firewalls, and Plivo's service status page.
- Platform Limitations:
- Trial Account: Can only send to verified sandbox numbers. Limited throughput. Plivo branding may be added to messages.
- Sender ID Rules: Vary significantly by country. US/Canada generally require Plivo numbers. Alphanumeric IDs may need registration elsewhere.
- Rate Limits: Plivo imposes limits on API calls per second/minute. High-volume sending requires handling potential rate limit errors (HTTP 429).
- Version Compatibility: Ensure your Node.js version is compatible with the versions of Fastify and the Plivo SDK specified in
package.json
. Check the respective libraries' documentation for compatibility notes if issues arise. - Edge Cases:
- Very long messages splitting into many segments.
- Messages with complex Unicode characters.
- Destination numbers in regions with delivery issues or regulations.
- Workarounds:
- For trial accounts, always verify numbers first.
- For rate limits, implement client-side throttling or queueing if sending bulk messages.
12. Deployment and CI/CD
Basic Deployment (Conceptual):
- Build/Preparation: Ensure all dependencies are installed (
npm install --production
can skip devDependencies). - Environment Configuration: Set the necessary environment variables (
PLIVO_AUTH_ID
,PLIVO_AUTH_TOKEN
,PLIVO_SENDER_NUMBER
,PORT
,NODE_ENV=production
) on the target server or container environment. Do not deploy the.env
file directly; use the platform's environment variable management. - Process Management: Use a process manager like PM2 or rely on container orchestration (Docker, Kubernetes) to run and manage the Node.js process (
node src/server.js
).- PM2 Example:
# Install PM2 globally npm install -g pm2 # Start the application pm2 start src/server.js --name fastify-plivo-sms # View logs pm2 logs fastify-plivo-sms # Monitor processes pm2 monit
- PM2 Example:
- Reverse Proxy (Recommended): Set up Nginx or similar to act as a reverse proxy in front of your Fastify app. This handles SSL termination (HTTPS), load balancing (if scaling), and can serve static files if needed.
CI/CD Pipeline (Conceptual):
A typical pipeline using services like GitHub Actions, GitLab CI, or Jenkins:
- Trigger: On push/merge to the main branch.
- Checkout Code: Get the latest source code.
- Setup Node.js: Specify the required Node.js version.
- Install Dependencies:
npm ci
(usespackage-lock.json
for deterministic installs). - Linting/Testing: Run code linters (e.g., ESLint) and automated tests (unit, integration).
- Build (if necessary): If using TypeScript or a build step.
- Package: Create a deployment artifact (e.g., Docker image, zip archive).
- Deploy: Push the artifact to the target environment (e.g., cloud provider, server).
- Post-Deploy Steps: Run database migrations (if applicable), restart services, run health checks.