Skip to main content
PolyVal uses a simple, intuitive schema definition structure that makes validation easy to write and maintain. Each field in your schema is defined with a type and optional validation rules.

Basic structure

A PolyVal schema is a plain JavaScript object where each key represents a field name:
import { validate } from 'polyval';

const userSchema = {
  username: {
    type: 'string',
    required: true,
    min: 3,
    max: 20
  },
  email: {
    type: 'string',
    required: true,
    email: true
  },
  age: {
    type: 'number',
    min: 18
  }
};

Supported types

Every field must specify one of four supported types:
  • string - Text values
  • number - Numeric values
  • boolean - True/false values
  • date - Date objects
The type property is required for every field in your schema.

String validation

String fields support a wide range of validation rules:

Length validation

const schema = {
  username: {
    type: 'string',
    min: 3,        // Minimum length
    max: 20        // Maximum length
  },
  pin: {
    type: 'string',
    length: 6      // Exact length required
  }
};

Format validation

const schema = {
  email: {
    type: 'string',
    email: true    // Email format validation
  },
  website: {
    type: 'string',
    url: true      // URL format validation
  },
  id: {
    type: 'string',
    uuid: true     // UUID format validation
  },
  userId: {
    type: 'string',
    cuid: true     // CUID format validation
  },
  timestamp: {
    type: 'string',
    datetime: true // ISO 8601 datetime format
  },
  serverIp: {
    type: 'string',
    ip: 'v4'       // IP address format ('v4' or 'v6')
  }
};

Pattern validation

const schema = {
  username: {
    type: 'string',
    regex: '^[a-zA-Z0-9]+$',  // Only alphanumeric characters
    startsWith: 'user_',       // Must start with 'user_'
    endsWith: '_verified'      // Must end with '_verified'
  },
  phoneNumber: {
    type: 'string',
    numeric: true              // Only numeric characters allowed
  }
};
The regex property accepts a string pattern, not a RegExp object. The string will be converted to a RegExp internally.

Number validation

Number fields support range validation:
const schema = {
  age: {
    type: 'number',
    required: true,
    min: 18,       // Minimum value
    max: 120       // Maximum value
  },
  score: {
    type: 'number',
    min: 0,
    max: 100
  }
};

Date validation

Date fields support minimum and maximum date constraints:
const schema = {
  birthdate: {
    type: 'date',
    required: true,
    max: Date.now(),           // Must be in the past
    min: new Date('1900-01-01').getTime()
  },
  appointmentDate: {
    type: 'date',
    min: Date.now()            // Must be in the future
  }
};
Date validation uses numeric timestamps. Use Date.now() or new Date().getTime() to get timestamp values.

Boolean validation

Boolean fields can be required and checked for specific values:
const schema = {
  acceptTerms: {
    type: 'boolean',
    required: true,
    equals: true     // Must be true (e.g., checkbox must be checked)
  },
  optOut: {
    type: 'boolean',
    equals: false    // Must be false
  }
};

Field comparison

Compare a field’s value against another field in the data:
const schema = {
  password: {
    type: 'string',
    required: true,
    min: 8
  },
  confirmPassword: {
    type: 'string',
    required: true,
    equals: 'password'         // Must match the 'password' field
  },
  oldPassword: {
    type: 'string',
    notEquals: 'password'      // Must NOT match the 'password' field
  }
};
Field comparison rules are useful for password confirmation, ensuring unique values, or validating related fields.

Custom validators

Add your own validation logic using custom validators:
const schema = {
  username: {
    type: 'string',
    required: true,
    customValidators: [
      {
        validator: (value, data) => {
          // Custom validation logic
          if (value.toLowerCase() === 'admin') {
            return 'This username is not available';
          }
          return undefined; // Return undefined for successful validation
        },
        messageKey: 'noAdminUsername'  // Optional key for custom messages
      }
    ]
  }
};

Custom validator structure

Each custom validator is an object with two properties:
  • validator - A function that receives (value, data) and returns:
    • string - Error message if validation fails
    • undefined - If validation passes
  • messageKey - Optional key to reference this validator in customMessages

Accessing other fields

Custom validators receive the entire data object as the second parameter:
const schema = {
  confirmPassword: {
    type: 'string',
    required: true,
    customValidators: [
      {
        validator: (value, data) => {
          // Access other fields via the data object
          if (value === data.password + '123') {
            return 'Password is too predictable';
          }
          return undefined;
        },
        messageKey: 'predictablePassword'
      }
    ]
  }
};

Complete example

Here’s a comprehensive schema demonstrating multiple validation rules:
import { validate } from 'polyval';

const userRegistrationSchema = {
  username: {
    type: 'string',
    required: true,
    min: 3,
    max: 20,
    regex: '^[a-zA-Z0-9]+$',
    customValidators: [{
      validator: (value) => {
        return value.toLowerCase() !== 'admin' 
          ? undefined 
          : 'Admin username is not available';
      },
      messageKey: 'noAdminUsername'
    }]
  },
  email: {
    type: 'string',
    required: true,
    email: true
  },
  age: {
    type: 'number',
    min: 18,
    required: false
  },
  password: {
    type: 'string',
    required: true,
    min: 8,
    regex: '^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]+$'
  },
  confirmPassword: {
    type: 'string',
    required: true,
    equals: 'password'
  },
  acceptTerms: {
    type: 'boolean',
    required: true,
    equals: true
  }
};

const userData = {
  username: 'jo',
  email: 'invalid-email',
  age: 16,
  password: '123',
  confirmPassword: '456',
  acceptTerms: false
};

const errors = validate(userRegistrationSchema, userData, { lang: 'en' });
console.log(errors);

TypeScript support

PolyVal includes full TypeScript definitions. Import the SimpleValidationSchema interface:
import { SimpleValidationSchema, validate } from 'polyval';

const schema: SimpleValidationSchema = {
  username: {
    type: 'string',
    required: true,
    min: 3
  }
};
TypeScript will provide autocomplete and type checking for all validation rules based on the field type you specify.

Build docs developers (and LLMs) love