This guide provides a complete walkthrough for building a production-ready Node.js application using the Express framework to send SMS messages via the Vonage Messages API. We will cover everything from project setup and core implementation to security, error handling, testing, and deployment considerations.
By the end of this guide, you will have a functional API endpoint capable of accepting a phone number and message, securely sending the SMS using Vonage, and handling potential issues gracefully. This forms a solid foundation for integrating SMS capabilities into larger applications for notifications, alerts, verification, or other communication needs.
Project Overview and Goals
What We're Building:
A simple REST API built with Node.js and Express. This API will expose a single endpoint (POST /send-sms
) that accepts a recipient phone number and a message body. Upon receiving a request, the API will use the Vonage Messages API to send the specified SMS message to the recipient.
Problem Solved:
This project provides a reusable, server-side component for programmatically sending SMS messages, abstracting the direct interaction with the Vonage API into a simple API call within your own infrastructure.
Technologies Used:
- Node.js: A JavaScript runtime environment for building server-side applications.
- Express: A minimal and flexible Node.js web application framework used to create the API server and routes.
- Vonage Node.js Server SDK: The official library for interacting with Vonage APIs, specifically the Messages API in this case.
- dotenv: A module to load environment variables from a
.env
file intoprocess.env
, keeping sensitive credentials out of the codebase. - joi: A library for robust data validation.
System Architecture:
A client application (like Postman or another service) sends an HTTP POST request to the /send-sms
endpoint of the Node.js/Express API. The API uses the Vonage SDK, configured with credentials read from environment variables (or a .env
file), to communicate with the Vonage Messages API. Vonage then sends the SMS message to the recipient's phone.
Prerequisites:
- Node.js and npm (or yarn): Installed on your development machine. Download from nodejs.org.
- Vonage API Account: Sign up for free at Vonage API Dashboard. You get free credit to start testing.
- A Vonage Virtual Number: You need to rent a Vonage number capable of sending SMS messages. You can do this through the Vonage Dashboard after signing up.
- Basic understanding of JavaScript and REST APIs.
- A text editor or IDE (e.g., VS Code).
- (Optional but Recommended) Postman or curl: For testing the API endpoint.
Final Outcome:
A running Node.js Express application with a secure endpoint (/send-sms
) that successfully sends SMS messages via Vonage when provided with a valid recipient number, message, and correct Vonage credentials. The application will include robust validation, error handling, and logging.
1. Setting up the Project
Let's initialize our Node.js project and install the necessary dependencies.
-
Create Project Directory: Open your terminal or command prompt and create a new directory for the project, then navigate into it.
mkdir vonage-sms-sender cd vonage-sms-sender
-
Initialize Node.js Project: Initialize the project using npm (or yarn). This creates a
package.json
file to manage dependencies and scripts.npm init -y
(If using yarn:
yarn init -y
) -
Install Dependencies: Install Express for the web server, the Vonage Server SDK,
dotenv
for environment variables, andjoi
for validation.npm install express @vonage/server-sdk dotenv joi
(If using yarn:
yarn add express @vonage/server-sdk dotenv joi
) -
Create Project Structure: Create the basic files and folders needed for the application.
# For Linux/macOS touch index.js .env .gitignore smsService.js # For Windows (Command Prompt) type nul > index.js type nul > .env type nul > .gitignore type nul > smsService.js # For Windows (PowerShell) New-Item index.js -ItemType File New-Item .env -ItemType File New-Item .gitignore -ItemType File New-Item smsService.js -ItemType File
index.js
: The main entry point for our Express application.smsService.js
: A module dedicated to handling Vonage interactions..env
: Stores sensitive configuration like API keys and secrets (will be configured later). Never commit this file to version control..gitignore
: Specifies intentionally untracked files that Git should ignore.
-
Configure
.gitignore
: Open.gitignore
and add the following lines to prevent committing sensitive files and unnecessary directories:# .gitignore # Dependencies node_modules/ # Environment variables .env # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Optional editor directories .vscode/ .idea/
Why? Keeping
node_modules
out prevents bloating the repository, and keeping.env
out prevents accidentally exposing secret credentials. -
Add Start Script (Optional but Recommended): Open
package.json
and add astart
script within thescripts
object for easily running the application. Yourpackage.json
will look something like this (exact versions may differ):{ "name": "vonage-sms-sender", "version": "1.0.0", "description": "API to send SMS using Node.js, Express, and Vonage", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "vonage", "sms", "node", "express" ], "author": "", "license": "ISC", "dependencies": { "@vonage/server-sdk": "^3.14.0", "dotenv": "^16.4.5", "express": "^4.19.2", "joi": "^17.13.1" } }
(Note: The versions shown above are examples.
npm install
will add the latest compatible versions.)Now you can run the app using
npm start
(oryarn start
).
2. Implementing Core Functionality (SMS Sending Logic)
We'll encapsulate the Vonage interaction logic within its own module (smsService.js
) for better organization.
-
Edit
smsService.js
: OpensmsService.js
and add the following code. This module initializes the Vonage client and exports a function to send SMS messages.// smsService.js const { Vonage } = require('@vonage/server-sdk'); const { Text } = require('@vonage/messages'); // Import Text message type const fs = require('fs'); // Used if reading private key content directly // Initialize Vonage client from environment variables // Ensure VONAGE_APPLICATION_ID and VONAGE_PRIVATE_KEY_PATH are set in your .env file // The SDK can accept the path directly in the privateKey property. const vonage = new Vonage({ applicationId: process.env.VONAGE_APPLICATION_ID, privateKey: process.env.VONAGE_PRIVATE_KEY_PATH, // Pass the path to the key file }); // Retrieve Vonage number from environment variables const vonageNumber = process.env.VONAGE_NUMBER; /** * Sends an SMS message using the Vonage Messages API. * @param {string} recipientNumber - The E.164 formatted phone number to send the SMS to. * @param {string} messageText - The text content of the SMS message. * @returns {Promise<object>} - A promise that resolves with the Vonage API response on success. * @throws {Error} - Throws an error if sending fails or required variables are missing. */ async function sendSms(recipientNumber, messageText) { // Input validation (basic checks, detailed validation handled by Joi in API layer) if (!process.env.VONAGE_APPLICATION_ID || !process.env.VONAGE_PRIVATE_KEY_PATH) { throw new Error('Vonage Application ID or Private Key Path missing in environment variables.'); } // Check if the private key file exists before attempting to use it (optional but good practice) if (!fs.existsSync(process.env.VONAGE_PRIVATE_KEY_PATH)) { throw new Error(`Private key file not found at path: ${process.env.VONAGE_PRIVATE_KEY_PATH}`); } if (!vonageNumber) { throw new Error('Vonage sending number (VONAGE_NUMBER) missing in environment variables.'); } if (!recipientNumber) { throw new Error('Recipient number is required.'); // Should be caught by Joi earlier } if (!messageText) { throw new Error('Message text is required.'); // Should be caught by Joi earlier } console.log(`Attempting to send SMS from ${vonageNumber} to ${recipientNumber}`); try { const response = await vonage.messages.send( new Text({ text: messageText, to: recipientNumber, from: vonageNumber, // Must be a Vonage virtual number associated with your Application ID channel: 'sms', // Specify SMS channel }) ); console.log(`SMS submitted successfully with Message UUID: ${response.messageUuid}`); return response; // Contains message_uuid } catch (error) { // Log the detailed error from Vonage if available const errorMessage = error?.response?.data?.title || error.message; const errorDetails = error?.response?.data?.detail || JSON.stringify(error?.response?.data); // Capture more detail if present console.error(`Error sending SMS via Vonage: ${errorMessage}. Details: ${errorDetails}`, error); // Rethrow a more specific error throw new Error(`Failed to send SMS: ${errorMessage}`); } } module.exports = { sendSms };
Why this structure?
- Separation of Concerns: Keeps Vonage-specific logic separate from the Express routing logic.
- Initialization: Initializes the Vonage client once, using credentials from environment variables. The SDK conveniently handles reading the private key file when given the path.
- Messages API: Uses
vonage.messages.send
with theText
object, the current recommended approach. - Async/Await: Uses modern JavaScript promises.
- Error Handling: Includes a
try...catch
block with more detailed logging of potential Vonage API errors. - Input Checks: Redundant basic checks are kept, though the primary validation now happens in the API layer with Joi. Added an optional file existence check for the private key.
3. Building the API Layer
Now, let's create the Express server and the API endpoint in index.js
, incorporating robust validation from the start.
-
Edit
index.js
: Openindex.js
and implement the Express server and the/send-sms
route with Joi validation.// index.js require('dotenv').config(); // Load environment variables from .env file const express = require('express'); const Joi = require('joi'); // For input validation const { sendSms } = require('./smsService'); // Import our SMS sending function const app = express(); const PORT = process.env.PORT || 3000; // Use port from .env or default to 3000 // Middleware app.use(express.json()); // Enable parsing JSON request bodies app.use(express.urlencoded({ extended: true })); // Enable parsing URL-encoded request bodies // Simple logging middleware (optional) app.use((req, res, next) => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`); next(); }); // --- API Endpoints --- // Health Check Endpoint app.get('/health', (req, res) => { res.status(200).json({ status: 'UP', timestamp: new Date().toISOString() }); }); // Define Joi schema for input validation const sendSmsSchema = Joi.object({ // Basic E.164 validation (allows '+' followed by 1 to 15 digits) // Note: This is a basic pattern. For robust global number validation, // consider libraries like libphonenumber-js (see Section 8). to: Joi.string().pattern(/^\+[1-9]\d{1,14}$/).required().messages({ 'string.pattern.base': '"to" must be a valid phone number in E.164 format (e.g., +12345678900).', 'any.required': '"to" is a required field.' }), // Max SMS length is technically ~1600 chars for concatenated messages, // but individual segments are shorter. Setting a reasonable limit here. message: Joi.string().min(1).max(1600).required().messages({ 'string.min': '"message" cannot be empty.', 'string.max': '"message" exceeds maximum length.', 'any.required': '"message" is a required field.' }) }); // Send SMS Endpoint app.post('/send-sms', async (req, res) => { // Validate request body against the schema const { error, value } = sendSmsSchema.validate(req.body); if (error) { console.error('Validation Error:', error.details[0].message); // Return a 400 Bad Request error with validation details return res.status(400).json({ success: false, error: 'Invalid input.', details: error.details[0].message }); } // Use the validated values const { to, message } = value; try { console.log(`Received request to send SMS to: ${to}`); const vonageResponse = await sendSms(to, message); // Call the service function res.status(200).json({ success: true, message: 'SMS submitted successfully.', message_uuid: vonageResponse.messageUuid // Include the message UUID from Vonage }); } catch (error) { console.error('Error in /send-sms endpoint:', error.message); // Determine appropriate status code based on error type if possible // For now, default to 500 Internal Server Error res.status(500).json({ success: false, error: 'Failed to send SMS.', details: error.message // Provide detail from the caught error }); } }); // --- Error Handling Middleware (Basic) --- // This catches errors not handled in specific routes (e.g., programming errors) app.use((err, req, res, next) => { console.error('Unhandled Error:', err.stack); res.status(500).json({ success: false, error: 'Something went wrong on the server.' }); }); // Export the app instance for testing purposes module.exports = app; // Start the server only if not in test mode if (process.env.NODE_ENV !== 'test') { app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); console.log(`API endpoint available at http://localhost:${PORT}/send-sms`); // Check for necessary environment variables on startup if (!process.env.VONAGE_APPLICATION_ID || !process.env.VONAGE_PRIVATE_KEY_PATH || !process.env.VONAGE_NUMBER) { console.warn('\x1b[33m%s\x1b[0m', 'Warning: One or more Vonage environment variables (VONAGE_APPLICATION_ID, VONAGE_PRIVATE_KEY_PATH, VONAGE_NUMBER) are missing. SMS sending will likely fail.'); } else { console.log('Vonage credentials loaded successfully.'); } }); }
-
Testing the Endpoint (
curl
Example): Once the server is running (and Vonage is configured in the next step), you can test the endpoint usingcurl
from your terminal:curl -X POST http://localhost:3000/send-sms \ -H "Content-Type: application/json" \ -d '{ "to": "+12345678900", "message": "Hello from Node.js and Vonage!" }'
IMPORTANT: You must replace
+12345678900
with a real phone number in E.164 format. If you are using a Vonage trial account, this number must also be whitelisted in your Vonage dashboard (see Section 11: Troubleshooting for details).Expected Success Response (JSON):
{ "success": true, "message": "SMS submitted successfully.", "message_uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" }
Expected Error Response (JSON - e.g., invalid phone number):
{ "success": false, "error": "Invalid input.", "details": "\"to\" must be a valid phone number in E.164 format (e.g., +12345678900)." }
4. Integrating with Vonage (Credentials & Setup)
This is a critical step. You need to configure your Vonage account correctly and provide the necessary credentials to your application via environment variables.
-
Sign Up/Log In: Ensure you have a Vonage API account: Vonage API Dashboard.
-
Create a Vonage Application: The Messages API requires an ""Application"" for authentication using a private key.
- Navigate to Applications in the left-hand menu of the Vonage Dashboard.
- Click + Create a new application.
- Give your application a descriptive name (e.g.,
Node SMS Sender App
). - Click Generate public and private key. This will automatically download the
private.key
file. Save this file securely within your project directory (e.g., in the root, but ensure it's in your.gitignore
). The public key is stored by Vonage. - Under Capabilities, find Messages and toggle it ON.
- You'll see fields for Inbound URL and Status URL. For sending SMS only, these can initially be left blank or pointed to placeholder URLs (e.g.,
https://example.com/inbound
,https://example.com/status
). They are required if you want to receive SMS or get delivery receipts.
- You'll see fields for Inbound URL and Status URL. For sending SMS only, these can initially be left blank or pointed to placeholder URLs (e.g.,
- Click Generate application.
- You will be taken to the application details page. Copy the Application ID – you'll need this.
-
Link Your Vonage Number: You need to associate your Vonage virtual number with the Application you just created.
- Navigate to Numbers > Your numbers in the Vonage Dashboard.
- Find the Vonage number you want to use for sending SMS.
- Click the Manage or Edit button (often a pencil icon) next to the number.
- In the Forwarding or Application section, select the Application you created (e.g.,
Node SMS Sender App
) from the dropdown list. - Click Save.
-
Set Default SMS API (Crucial): Ensure your account is configured to use the Messages API for SMS by default.
- Navigate to API settings from the main Dashboard page or left menu.
- Scroll down to the SMS settings section.
- Under Default SMS Setting, select Messages API.
- Click Save changes. (Why? Vonage has two SMS APIs. The SDK code we used targets the Messages API. Setting this default ensures webhooks (if used later) and potentially other interactions use the correct format.)
-
Configure Environment Variables (
.env
file): Open the.env
file in your project root and add the credentials you obtained.# .env - Vonage Credentials & App Configuration # --- Vonage API Configuration --- # Found on the Vonage Dashboard under ""Applications"" -> Your Application Name VONAGE_APPLICATION_ID=YOUR_APPLICATION_ID_HERE # Path to the private key file downloaded when creating the Vonage Application. # Use a relative path from the project root, e.g., ./private.key if it's in the root. # Ensure the Node process has read permissions for this file. VONAGE_PRIVATE_KEY_PATH=./private.key # Your Vonage virtual number (in E.164 format, e.g., +14155550100) # This number must be linked to the VONAGE_APPLICATION_ID in the Vonage dashboard. VONAGE_NUMBER=YOUR_VONAGE_NUMBER_HERE # --- Server Configuration --- # Port the Express server will listen on PORT=3000 # --- Node Environment --- # Set to 'production' in deployed environments # NODE_ENV=development # --- Security (Optional - See Section 7) --- # Example: API Key for securing your endpoint # API_KEY=your-secret-api-key-here # --- Monitoring (Optional - See Section 10) --- # Example: Sentry DSN # SENTRY_DSN=your_sentry_dsn_here
- Replace
YOUR_APPLICATION_ID_HERE
with the Application ID you copied. - Replace
./private.key
with the actual relative path to your downloadedprivate.key
file. Make sure this path is correct relative to where you runnode index.js
. - Replace
YOUR_VONAGE_NUMBER_HERE
with your Vonage virtual number in E.164 format (e.g.,+14155550100
). - Security: Ensure the
.env
file is included in your.gitignore
and never committed to version control. Use platform-specific secret management tools for production deployments.
- Replace
5. Implementing Error Handling, Logging, and Retry Mechanisms
Our current code has improved error handling and basic logging. Let's discuss refinements.
- Consistent Error Strategy: The
/send-sms
endpoint uses Joi for validation errors (400) and atry...catch
block for operational errors (500), returning standardized JSON responses ({ success: false, error: '...', details: '...' }
). This is good practice. ThesmsService
throws specific errors which are caught and logged by the API layer. - Logging: We use
console.log
andconsole.error
. For production, consider a more robust logging library like Winston or Pino. These enable:- Different log levels (debug, info, warn, error).
- Structured logging (JSON format), making logs easier to parse and analyze by log management systems.
- Writing logs to files or external logging services (like Datadog, Logstash, etc.).
- Example with Winston (requires
npm install winston
):// Example: Replace console.log with a logger const winston = require('winston'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', // Control level via env var format: winston.format.combine( winston.format.timestamp(), winston.format.json() // Log in JSON format ), transports: [ // Always log to console new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), // Add colors for readability (optional) winston.format.simple() // Simple format for console ) }), // Add file transport for production if needed // new winston.transports.File({ filename: 'error.log', level: 'error' }), // new winston.transports.File({ filename: 'combined.log' }), ], // Handle uncaught exceptions and rejections exceptionHandlers: [ new winston.transports.Console(), // new winston.transports.File({ filename: 'exceptions.log' }) ], rejectionHandlers: [ new winston.transports.Console(), // new winston.transports.File({ filename: 'rejections.log' }) ] }); // Usage: replace console.log/error with logger.info/error/warn/debug // logger.info(`Server running on port ${PORT}`); // logger.error('Error in /send-sms endpoint:', { message: error.message, stack: error.stack }); // Log error object
- Retry Mechanisms: Directly calling an external API like Vonage can sometimes fail due to transient network issues or temporary service unavailability (e.g., 5xx errors from Vonage).
- Simple Approach: Implement a basic retry loop within the
sendSms
function (not shown for brevity, can add complexity and potentially delay API responses). - Robust Approach (Recommended for Production): For critical SMS messages, offload the sending task to a background job queue (e.g., using libraries like BullMQ or Agenda with Redis). The API endpoint would quickly add the job to the queue and return a success response (e.g., 202 Accepted). A separate worker process then picks up the job, attempts to send the SMS via
smsService.sendSms
, and implements sophisticated retry strategies (like exponential backoff with jitter) if the attempt fails due to transient errors. This significantly improves API responsiveness and reliability for the client. Implementing a full queue is beyond this basic guide's scope but is a crucial consideration for production systems handling significant volume or requiring high reliability.
- Simple Approach: Implement a basic retry loop within the
6. Database Schema and Data Layer
This specific project only sends SMS messages based on API requests and doesn't require storing persistent data like message history, user information, or tracking delivery status. Therefore, no database schema or data layer is needed for this core functionality.
If you were to extend this application to, for example:
- Track sent messages and their Vonage
message_uuid
. - Store delivery status updates (received via webhooks).
- Manage contacts or user preferences.
- Handle inbound messages.
You would then need to:
- Choose a database (e.g., PostgreSQL, MySQL, MongoDB).
- Design a schema (e.g., a
messages
table with columns likeid
,recipient
,sender
,body
,status
,vonage_message_uuid
,error_message
,created_at
,updated_at
). - Implement a data access layer using an ORM (like Prisma, Sequelize for SQL, or Mongoose for MongoDB) or a database driver (like
pg
ormysql2
). - Set up database migrations to manage schema changes over time.
7. Adding Security Features
Securing your API is vital, especially when dealing with external services that incur costs.
-
Input Validation and Sanitization: (Already Implemented)
- We've implemented robust input validation using Joi in Section 3. This prevents malformed requests and basic injection attempts by ensuring
to
andmessage
conform to expected formats and constraints. - The E.164 regex used (
^\+[1-9]\d{1,14}$
) is a basic check. For truly global applications accepting diverse inputs, consider using a dedicated library likelibphonenumber-js
for more comprehensive parsing and validation (see Section 8). - Sanitization: Since the
message
content is passed directly to the Vonage SDK (which should handle it safely) and not interpreted or stored in a way vulnerable to XSS (in this basic example), explicit sanitization might not be critical here. However, always sanitize input if it's reflected back to users, stored in HTML, or used in database queries constructed manually.
- We've implemented robust input validation using Joi in Section 3. This prevents malformed requests and basic injection attempts by ensuring
-
Rate Limiting: Protect against brute-force attacks, accidental loops, and API abuse.
- Install:
npm install express-rate-limit
- Example in
index.js
(apply this middleware before your API routes):// index.js (near the top, after other middleware like express.json) const rateLimit = require('express-rate-limit'); const apiLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per windowMs to the /send-sms endpoint standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers legacyHeaders: false, // Disable the `X-RateLimit-*` headers message: { success: false, error: 'Too many requests, please try again after 15 minutes.' } }); // Apply the rate limiting middleware specifically to the send-sms route app.use('/send-sms', apiLimiter); // Or apply to all routes if needed: app.use(apiLimiter);
- Install:
-
Authentication/Authorization: The current endpoint is open. In any real application, you must protect it to ensure only authorized clients can use it. Common methods include:
- API Keys: A simple method suitable for server-to-server communication. Generate a strong, random secret key. Require clients to send this key in a custom HTTP header (e.g.,
X-API-Key
orAuthorization: ApiKey YOUR_KEY
). Validate the key on the server using middleware.// Example Middleware in index.js (apply before the /send-sms route, after rate limiter) const API_KEY = process.env.API_KEY; // Load expected key from .env function authenticateKey(req, res, next) { const providedKey = req.headers['x-api-key']; // Or parse from Authorization header if (!API_KEY) { // If API key isn't configured on the server, block all requests console.error('Security Error: API_KEY is not set in environment variables.'); return res.status(500).json({ success: false, error: 'Server configuration error.' }); } if (providedKey && providedKey === API_KEY) { next(); // Key is valid, proceed } else { res.status(401).json({ success: false, error: 'Unauthorized: Invalid or missing API Key.' }); } } // Only apply authentication if an API_KEY is configured if (API_KEY) { app.use('/send-sms', authenticateKey); // Apply middleware console.log('API Key authentication enabled for /send-sms'); } else { console.warn('\x1b[33m%s\x1b[0m', 'Warning: API_KEY environment variable not set. /send-sms endpoint is unsecured.'); }
- JWT (JSON Web Tokens): Suitable if your API serves authenticated users who have logged in via another part of your system. Clients send a token in the
Authorization: Bearer <token>
header. - OAuth 2.0: The standard framework for delegated authorization, often used when third-party applications need access to your API.
- API Keys: A simple method suitable for server-to-server communication. Generate a strong, random secret key. Require clients to send this key in a custom HTTP header (e.g.,
-
Secure Credential Management: Reiterate: Use environment variables (
.env
locally) and secure secret management solutions (like AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, HashiCorp Vault) in production environments. Never hardcode credentials (Vonage keys, API keys, database passwords) in your source code. -
HTTPS: Always use HTTPS for your API in production. This encrypts data in transit, protecting sensitive information like phone numbers, message content, and authentication tokens. HTTPS is typically handled by a reverse proxy (like Nginx or Caddy), a load balancer, or the PaaS platform hosting your application.
-
Dependency Management: Keep dependencies up-to-date to patch known vulnerabilities. Regularly run
npm audit
and apply fixes (npm audit fix
). Use tools like Snyk or Dependabot for automated vulnerability scanning. -
Security Headers: Use libraries like
helmet
(npm install helmet
) to set various HTTP headers that help protect against common web vulnerabilities (XSS, clickjacking, etc.).// index.js (near the top) const helmet = require('helmet'); app.use(helmet());
8. Handling Special Cases
- Phone Number Formatting: The Vonage API generally expects numbers in E.164 format (e.g.,
+14155550100
). Our Joi validation enforces a basic version of this. However, users might provide numbers in local formats. For more robust handling:- Use a library like
libphonenumber-js
(npm install libphonenumber-js
) to parse and validate numbers from various formats and potentially convert them to E.164.
// Example usage (conceptual) // const { parsePhoneNumberFromString } = require('libphonenumber-js'); // const phoneNumber = parsePhoneNumberFromString(userInputNumber, 'US'); // Provide default country context // if (phoneNumber && phoneNumber.isValid()) { // const e164Number = phoneNumber.format('E.164'); // Convert to +14155550100 // // Use e164Number // } else { // // Handle invalid number input // }
- Use a library like