Node.js10 min setupBeginner

Phone Validation Middleware for Express.js API

Create reusable middleware to validate phone numbers across your Express.js endpoints. Perfect for user registration, profile updates, and contact forms.

The Problem

Your API accepts phone numbers from multiple endpoints (registration, profile updates, contact forms), but there's no consistent validation. Invalid numbers slip through, causing issues downstream.

The Solution

Create a reusable Express middleware that validates phone numbers using the Phone Validator API. Apply it to any route that needs phone validation with a single line of code.

1Get Your API Key

Sign up on RapidAPI and get your API key for Phone Validator:

Get Free API Key →

2Install Dependencies

npm install express axios dotenv

3Create the Phone Validation Middleware

middleware/validatePhone.js

const axios = require('axios');

/**
 * Middleware to validate phone numbers using Phone Validator API
 * @param {string} fieldName - The field name in req.body (default: 'phone')
 */
const validatePhone = (fieldName = 'phone') => {
  return async (req, res, next) => {
    const phoneNumber = req.body[fieldName];
    
    // Check if phone number is provided
    if (!phoneNumber) {
      return res.status(400).json({
        success: false,
        error: `${fieldName} is required`
      });
    }
    
    try {
      // Call Phone Validator API
      const response = await axios.get(
        'https://phone-validator7.p.rapidapi.com/validate',
        {
          params: { phone: phoneNumber },
          headers: {
            'X-RapidAPI-Key': process.env.RAPIDAPI_KEY,
            'X-RapidAPI-Host': 'phone-validator7.p.rapidapi.com'
          },
          timeout: 5000 // 5 second timeout
        }
      );
      
      const validationResult = response.data;
      
      // Check if phone is valid
      if (!validationResult.valid) {
        return res.status(400).json({
          success: false,
          error: 'Invalid phone number. Please provide a valid phone number.'
        });
      }
      
      // Attach validation data to request for use in route handler
      req.phoneValidation = validationResult;
      
      // Continue to next middleware/route handler
      next();
      
    } catch (error) {
      console.error('Phone validation error:', error.message);
      
      // Fail open: allow request to continue if API is down
      // Change this behavior based on your requirements
      if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {
        console.warn('Phone validation timeout - allowing request');
        next();
      } else {
        res.status(500).json({
          success: false,
          error: 'Phone validation service temporarily unavailable'
        });
      }
    }
  };
};

module.exports = validatePhone;

4Configure Environment Variables

.env

RAPIDAPI_KEY=your_api_key_here

5Use the Middleware in Your Routes

routes/auth.js

const express = require('express');
const validatePhone = require('../middleware/validatePhone');

const router = express.Router();

// Registration endpoint with phone validation
router.post('/register', validatePhone('phone'), async (req, res) => {
  try {
    const { email, phone, password } = req.body;
    
    // Phone is already validated by middleware
    // Access validation data if needed
    const phoneData = req.phoneValidation;
    
    // Create user account
    const user = await User.create({
      email,
      phone: phoneData.number, // Use formatted number from API
      phoneCountry: phoneData.country_code,
      phoneCarrier: phoneData.carrier,
      password: await hashPassword(password)
    });
    
    res.status(201).json({
      success: true,
      message: 'Registration successful',
      user: {
        id: user.id,
        email: user.email,
        phone: user.phone
      }
    });
    
  } catch (error) {
    res.status(500).json({
      success: false,
      error: 'Registration failed'
    });
  }
});

// Profile update endpoint
router.put('/profile/phone', 
  authenticateUser, 
  validatePhone('newPhone'), 
  async (req, res) => {
    try {
      const { newPhone } = req.body;
      const phoneData = req.phoneValidation;
      
      await User.update(req.user.id, {
        phone: phoneData.number,
        phoneCountry: phoneData.country_code
      });
      
      res.json({
        success: true,
        message: 'Phone number updated successfully'
      });
      
    } catch (error) {
      res.status(500).json({
        success: false,
        error: 'Failed to update phone number'
      });
    }
  }
);

module.exports = router;

Complete Server Example

server.js

require('dotenv').config();
const express = require('express');
const authRoutes = require('./routes/auth');

const app = express();

// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Routes
app.use('/api/auth', authRoutes);

// Error handling
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({
    success: false,
    error: 'Something went wrong'
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Test Your Endpoint

Using cURL

Valid Phone:

curl -X POST http://localhost:3000/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "phone": "+15555551234",
    "password": "securePassword123"
  }'

Invalid Phone (should be rejected):

curl -X POST http://localhost:3000/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "phone": "1234567890",
    "password": "securePassword123"
  }'

Advanced Configuration

Restrict to Specific Countries

Only accept phone numbers from certain countries:

const validatePhone = (fieldName = 'phone', allowedCountries = []) => {
  return async (req, res, next) => {
    // ... existing validation code ...
    
    if (allowedCountries.length > 0) {
      if (!allowedCountries.includes(validationResult.country_code)) {
        return res.status(400).json({
          success: false,
          error: `Only phone numbers from ${allowedCountries.join(', ')} are accepted`
        });
      }
    }
    
    // ... continue ...
  };
};

// Usage: Only accept US and CA phone numbers
router.post('/register', validatePhone('phone', ['US', 'CA']), handler);

Block VOIP Numbers

Prevent VOIP or temporary numbers from registering:

// Check line type
if (validationResult.line_type === 'voip') {
  return res.status(400).json({
    success: false,
    error: 'VOIP numbers are not allowed'
  });
}

// Or only allow mobile
if (validationResult.line_type !== 'mobile') {
  return res.status(400).json({
    success: false,
    error: 'Only mobile numbers are accepted'
  });
}

Add Response Caching

Cache validation results to reduce API calls:

const NodeCache = require('node-cache');
const phoneCache = new NodeCache({ stdTTL: 86400 }); // 24 hours

// Check cache before API call
const cacheKey = `phone_${phoneNumber}`;
const cachedResult = phoneCache.get(cacheKey);

if (cachedResult) {
  req.phoneValidation = cachedResult;
  return next();
}

// After successful validation
phoneCache.set(cacheKey, validationResult);

Next Steps

  • 1.Get your free API key from RapidAPI
  • 2.Copy the middleware code and add to your project
  • 3.Apply middleware to routes that need phone validation
  • 4.Test with valid and invalid phone numbers

Ready to Implement?

Get your free API key and add phone validation to your Express.js API today.

Get Free API Key →