taptools/blog/Regex API Validation
RegexMay 16, 2026 · 8 min read

Regex Patterns for Validating API Payloads

Production-ready regex patterns for the most common API validation scenarios. Each pattern is explained and tested against edge cases.

Email validation

Email validation is notoriously difficult. The RFC 5322 standard allows for edge cases that most regex patterns don't handle. For production use a pragmatic pattern that covers 99.9% of real emails is better than a technically perfect but unreadable one.

// Pragmatic email regex — covers 99.9% of real emails
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/

// Test cases
emailRegex.test('user@example.com')        // ✅ true
emailRegex.test('user+tag@gmail.com')      // ✅ true
emailRegex.test('user.name@company.co.uk') // ✅ true
emailRegex.test('user@localhost')           // ❌ false (no TLD)
emailRegex.test('@example.com')            // ❌ false (no user)
emailRegex.test('user@.com')               // ❌ false (no domain)

// Usage in API validation
function validateEmail(email) {
  if (!emailRegex.test(email)) {
    throw new Error('Invalid email format')
  }
  return email.toLowerCase().trim()
}

URL validation

// URL validation — http and https only
const urlRegex = /^https?://(www.)?[-a-zA-Z0-9@:%._+~#=]{1,256}.[a-zA-Z0-9()]{1,6}([-a-zA-Z0-9()@:%_+.~#?&/=]*)$/

// Test cases
urlRegex.test('https://example.com')              // ✅
urlRegex.test('https://www.example.com/path?q=1') // ✅
urlRegex.test('http://localhost:3000')            // ✅
urlRegex.test('ftp://example.com')               // ❌ (ftp not allowed)
urlRegex.test('not-a-url')                       // ❌

// Alternative — use URL constructor for better validation
function isValidUrl(string) {
  try {
    const url = new URL(string)
    return url.protocol === 'http:' || url.protocol === 'https:'
  } catch {
    return false
  }
}

UUID validation

// UUID v4 validation
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i

// Any UUID version
const anyUuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i

// Test cases
uuidRegex.test('110e8400-e29b-41d4-a716-446655440000') // ✅
uuidRegex.test('not-a-uuid')                           // ❌

// API route validation example
app.get('/users/:id', (req, res) => {
  if (!uuidRegex.test(req.params.id)) {
    return res.status(400).json({ error: 'Invalid user ID format' })
  }
  // proceed with valid UUID
})

Phone number validation

// International phone number (E.164 format)
const phoneE164 = /^+[1-9]d{1,14}$/

// US phone number
const phoneUS = /^(+1)?[-.s]?(?d{3})?[-.s]?d{3}[-.s]?d{4}$/

// Generic — 7-15 digits with optional + prefix
const phoneGeneric = /^+?[ds-().]{7,20}$/

// Test E.164
phoneE164.test('+14155552671')  // ✅
phoneE164.test('+44 7700 900000') // ❌ (spaces not allowed in E.164)

// For international APIs always request E.164 format
// It removes ambiguity about country codes and formatting

Date format validation

// ISO 8601 date (YYYY-MM-DD)
const isoDate = /^d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]d|3[01])$/

// ISO 8601 datetime
const isoDateTime = /^d{4}-d{2}-d{2}Td{2}:d{2}:d{2}(.d+)?(Z|[+-]d{2}:d{2})$/

// Test cases
isoDate.test('2026-05-15')     // ✅
isoDate.test('2026-13-45')     // ❌ invalid month/day
isoDate.test('15/05/2026')     // ❌ wrong format

// Better — validate and parse together
function parseIsoDate(dateStr) {
  if (!isoDate.test(dateStr)) {
    throw new Error('Date must be in YYYY-MM-DD format')
  }
  const date = new Date(dateStr)
  if (isNaN(date.getTime())) {
    throw new Error('Invalid date value')
  }
  return date
}

Password strength validation

// Password strength — at least 8 chars, 
// one uppercase, one lowercase, one digit, one special char
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[@$!%*?&])[A-Za-zd@$!%*?&]{8,}$/

// Or check each requirement separately (better UX)
function validatePassword(password) {
  const checks = {
    length:    password.length >= 8,
    uppercase: /[A-Z]/.test(password),
    lowercase: /[a-z]/.test(password),
    digit:     /d/.test(password),
    special:   /[@$!%*?&]/.test(password),
  }
  
  const failed = Object.entries(checks)
    .filter(([, pass]) => !pass)
    .map(([rule]) => rule)
  
  return { valid: failed.length === 0, failed, checks }
}

Test your regex patterns instantly

Our regex tester shows matches highlighted in real time as you type.

Open Regex Tester →