Validate data


Keywords
validator, validators, xvalidators
Install
npm install xvalidators@0.2.2

Documentation

xvalidators

  • xvalidators is a lightweight JavaScript validation library designed for validating objects, arrays, and deeply nested data structures.
  • It supports built-in rules with fully customizable error messages:
    • type (string, Date, number, integer, boolean)
    • format (email, phone number, URL, IP Address, RegExp)
    • min, max, enum
    • custom rules
  • It also supports multi-language error handling by allowing custom message injection per field.
  • With no dependencies, it's ideal for both frontend forms (React, Angular, Vue) and backend APIs.

📦 Key Features

  • Data Type validation: string, Date, number, integer, boolean
  • Format validation (for string): email, phone number, URL, IP Address, RegExp
  • Nested Object Validation: Supports deep validation of nested structures
  • Array Validation: Validate array items with itemType, along with min and max constraints
  • Custom Rules:
    • rule: for simple synchronous logic
    • custom: for advanced validation (return error message with error code, error description)
  • Custom Error Messages: Fully localized/custom error support per field/rule.
  • Multi-language Friendly: Error messages can be defined in any language.
  • Form-friendly: Designed for both backend and frontend use.

⚙️ Detailed Features

String Number Date Boolean Nested Object Array
✅ Required ✅ Required ✅ Required ✅ Required ✅ Required ✅ Required
✅ Enum ✅ Enum ✅ Enum
✅ Min Length ✅ Min ✅ Min ✅ Min Length
✅ Max Length ✅ Max ✅ Max ✅ Max Length
✅ Email ✅ gt (greater than) ✅ gt (greater than)
✅ URL ✅ lt (less than) ✅ lt (less than)
✅ IP v4 ✅ Precision Relative date:
✅ IP v6 ✅ Scale now ✅
✅ Phone today ✅
✅ Fax tomorrow ✅
✅ Regex match ✅ Integer yesterday ✅

🛠️ Advantages

  • Rich Features: Yes (Look at below Feature Comparison)
  • JSON Schema Support: Yes
  • Performance: Fast, very lightweight, rule-by-rule
  • Typescript/Javascript Support: Yes
  • Custom Validators: Yes
  • Integration: node, express, react, angular, vue
  • Validation Output: Structured Errors (JSON)
  • Size: Small
  • Dependencies: No
  • Learning Curve: Fast (standard JSON Schema)

🧱 Real Samples

🚀 Benchmark

See the benchmark source code at data-validation-benchmark

Rank Library Ops/sec RME (%) Samples Size (min+gz) Relative Speed (vs fastest) Times Slower than Ajv Note
🥇 1 Ajv 6,091,923 0.76% 100 📦 ~114 KB 🏆 1.00× (fastest) 🏆 1× ⚡ Fastest + Heavier bundle
🥈 2 xvalidators 1,246,188 1.29% 92 ⚡ ~3.8 KB ~20.46% of Ajv ~4.9× 🔥 Very Fast + Small
🥉 3 Zod 939,381 0.31% 96 🧱 ~25 KB ~15.42% of Ajv ~6.5× 🐇 Fast + Medium Size
4 Valibot 859,490 0.24% 95 ⚡ ~4 KB ~14.11% of Ajv ~7.1× 🐇 Fast + Small Size
5 Joi 344,710 0.37% 93 📦 ~80 KB ~5.56% of Ajv ~17.7× 🐢 Slow + Heavy Size
6 Yup 115,048 0.34% 91 🧱 ~28 KB ~1.89% of Ajv ~52.9× 🐢 Slowest + Medium Size + Frontend-oriented

🔍 Key Insights

✅ Ajv

  • Top performer with ~6.09 million ops/sec.
  • Best for JSON Schema validation, high-throughput services.
  • Ideal for performance-critical Node.js or edge runtimes.

✅ xvalidators

  • ~4.9x slower than Ajv, but ~1.3x faster than Zod, and even faster than Valibot.
  • xvalidators is focused on bundle small size + performance, good for frontend.
  • Excellent TypeScript inference, flexible custom rules.
  • Very good for internal tools, low-code platforms, or apps that require typed validation

⚖️ Zod vs. Valibot

  • Nearly similar in ops/sec, suggesting similar architecture or design trade-offs.
  • Good for TypeScript-first developer experience but noticeably slower than Ajv/xvalidators.
  • Both offer great DX.
  • Valibot is focused on bundle size + performance, good for frontend.
  • Zod still preferred if you need ecosystem maturity and developer ergonomics.

❌ Joi and Yup

  • Significantly slower, not suited for performance-sensitive applications.
  • Useful in some backend contexts (Joi) or form validation (Yup), but not recommended when performance matters.

🏁 Recommendation by Use Case

Use Case Library Reason
High-throughput backend APIs Ajv Fastest JSON Schema validator
Minimal frontend apps with type-safe apps and custom rules xvalidators Good speed, excellent TypeScript integration
Minimal frontend apps Valibot Lightweight and efficient
DX-focused development Zod Clean syntax, popular, ideal for prototypes
Legacy/enterprise backend apps Joi Powerful features, but low performance
Form validation in React (Formik) Yup Integrated with form tools, but slow

📌 Summary

  • If you need speed: → Ajv
  • If you want typescript + good speed + small: → xvalidators
  • If you prefer a big community support over speed: → Zod or Valibot
  • If you already use Formik or legacy stack: → Yup or Joi

📊 Feature Comparison

Feature / Library Ajv xvalidators Zod Valibot Joi Yup
Required
Object / Nested validation
Array validation
Email format: "email" format: "email" .email() string([email()]) .email() .email()
URL format: "uri" format: "url" .url() string([url()]) .uri() .url()
IPv4 check format: "ipv4" format: "ipv4" ⚠️ Regex only ⚠️ Regex only .ip({ version: ["ipv4"] }) ⚠️ Regex only
IPv6 check format: "ipv6" format: "ipv6" ⚠️ Regex only ⚠️ Regex only .ip({ version: ["ipv6"] }) ⚠️ Regex only
Phone number ⚠️ No built-in — regex only format: "phone" ⚠️ No built-in — regex only ⚠️ No built-in — regex only ⚠️ No built-in — use .pattern() or .custom() with phone regex ⚠️ No built-in — use .matches() with regex
Fax number ⚠️ No built-in — regex only format: "fax" ⚠️ No built-in — regex only ⚠️ No built-in — regex only ⚠️ No built-in — use .pattern() or .custom() with phone regex ⚠️ No built-in — use .matches() with regex
Regex match pattern pattern .regex() string([regex(...)]) .pattern() .matches()
Enum values enum enum z.enum([...]) enumType() .valid(a,b,c) .oneOf([...])
Min/Max length (string)
Number type
Min/Max value (number/date)
Precision (decimal places) ⚠️ multipleOf precision: n ⚠️ .multipleOf() / .refine() ⚠️ .refine() .precision(n) ⚠️ .test()
Scale (integer + fraction limits) ⚠️ Custom scale: n ⚠️ Custom ⚠️ Custom ⚠️ Partial via .precision() + .max() ⚠️ Custom
Date type format: "date" / "date-time" type: "date" | "datetime" z.date() / .datetime() date() .date() .date()
Relative date (now/today/tomorrow/yesterday) ⚠️ Custom keyword min: "now" | "today" | "tomorrow" | "yesterday" ⚠️ .refine() ⚠️ .refine() .min('now') / .max('now') + Date values ⚠️ Custom .min() / .max()
Performance ⚡ Fastest 🔥 Fast 🐇 Good 🐇 Good 🐢 Slower 🐢 Slower
Bundle size (browser) Large (~60KB+, tree-shakeable) Small (~4KB) Medium (~20KB) Small (~6–8KB) Large (~70KB+) Medium (~30KB)
Best use case API validation, JSON Schema compliance API validation, JSON Schema compliance, minimal frontend TS-safe runtime validation Lightweight TS-safe validation Rich backend business rules Frontend form validation

🧱 Samples

Sample 1

import { Attributes, StringMap, validate } from "xvalidators"

interface Resources {
  [key: string]: StringMap
}

const enResource: StringMap = {
  error_undefined: "{0} is not allowed to exist.",
  error_exp: "{0} does not match the regular expression.",
  error_type: "Invalid datatype. Type of {0} cannot be {1}.",

  error_required: "{0} is required.",
  error_minlength: "{0} cannot be less than {1} characters.",
  error_maxlength: "{0} cannot be greater than {1} characters.",

  error_email: "{0} is not a valid email address.",
  error_integer: "{0} is not a valid integer.",
  error_number: "{0} is not a valid number.",
  error_precision: "{0} has a valid precision. Precision must be less than or equal to {1}",
  error_scale: "{0} has a valid scale. Scale must be less than or equal to {1}",
  error_phone: "{0} is not a valid phone number.",
  error_fax: "{0} is not a valid fax number.",
  error_url: "{0} is not a valid URL.",
  error_ipv4: "{0} is not a valid ipv4.",
  error_ipv6: "{0} is not a valid ipv6.",

  error_min: "{0} must be greater than or equal to {1}.",
  error_max: "{0} must be less than or equal to {1}.",
  error_date: "{0} is not a valid date.",
  error_enum: "{0} must be one of {1}.",

  username: "Username",
  date_of_birth: "Date Of Birth",
  telephone: "Telephone",
  email: "Email",
  website: "Website",
  status: "User Status",
  credit_limit: "Credit Limit",
}

const viResource = {
  error_undefined: "{0} không được phép tồn tại.",
  error_exp: "{0} không khớp với biểu thức chính quy.",
  error_type: "Kiểu dữ liệu không hợp lệ. Kiểu của {0} không thể là {1}.",

  error_required: "{0} là bắt buộc.",
  error_minlength: "{0} không được ít hơn {1} ký tự.",
  error_maxlength: "{0} không được nhiều hơn {1} ký tự.",

  error_email: "{0} không phải là địa chỉ email hợp lệ.",
  error_integer: "{0} không phải là số nguyên hợp lệ.",
  error_number: "{0} không phải là số hợp lệ.",
  error_precision: "{0} có độ chính xác không hợp lệ. Độ chính xác phải nhỏ hơn hoặc bằng {1}.",
  error_scale: "{0} có thang đo không hợp lệ. Thang đo phải nhỏ hơn hoặc bằng {1}.",
  error_phone: "{0} không phải là số điện thoại hợp lệ.",
  error_fax: "{0} không phải là số fax hợp lệ.",
  error_url: "{0} không phải là URL hợp lệ.",
  error_ipv4: "{0} không phải là địa chỉ IPv4 hợp lệ.",
  error_ipv6: "{0} không phải là địa chỉ IPv6 hợp lệ.",

  error_min: "{0} phải lớn hơn hoặc bằng {1}.",
  error_max: "{0} phải nhỏ hơn hoặc bằng {1}.",
  error_date: "{0} không phải là ngày hợp lệ.",
  error_enum: "{0} phải là một trong các giá trị sau: {1}.",

  username: "Tên người dùng",
  date_of_birth: "Ngày sinh",
  telephone: "Điện thoại",
  email: "Địa chỉ email",
  website: "Trang web",
  status: "Trạng thái người dùng",
  credit_limit: "Hạn mức tín dụng",
}

const resources: Resources = {
  en: enResource,
  vi: viResource,
}

function getResource(lang: string): StringMap {
  return resources[lang] || resources["en"]
}
const resource = getResource("en") // or "vi" for Vietnamese

interface User {
  id: string
  username: string
  email?: string
  phone?: string
  ip?: string
  dateOfBirth?: Date
  website?: string
  creditLimit?: number
  status?: string[]
}

const userSchema: Attributes = {
  id: {
    length: 40,
  },
  username: {
    required: true,
    length: 255,
    resource: "username",
  },
  email: {
    format: "email",
    required: true,
    length: 120,
    resource: "email",
  },
  phone: {
    format: "phone",
    required: true,
    length: 14,
    resource: "telephone",
  },
  ip: {
    format: "ipv4",
    length: 15,
  },
  website: {
    length: 255,
    format: "url",
    resource: "website",
  },
  dateOfBirth: {
    type: "datetime",
  },
  creditLimit: {
    type: "number",
    scale: 2,
    min: 1,
    max: 200000,
    resource: "credit_limit",
  },
  status: {
    type: "strings",
    enum: ["active", "inactive", "online", "offline", "away"],
    resource: "status",
  },
}

const invalidUser = {
  id: "12345678901234567890123456789012345678901", // 41 characters => maximum 40 => invalid
  // username: "james.howlett", // required => invalid
  email: "james.howlett@gmail", // invalid email
  phone: "abcd1234", // required => invalid
  ip: "abcd1234", // invalid => not required
  website: "invalid website",
  dateOfBirth: "1974-03-25", // valid date => the library will convert to date
  creditLimit: 10000000.255, // invalid precision and scale => precision must be less than or equal to 10 digits
  status: ["active", "busy"],
  age: 50, // does not exist in schema => invalid
}
let errors = validate(invalidUser, userSchema, resource)
console.log("Validate James Howlett: ", errors)

const user: User = {
  id: "1234567890123456789012345678901234567890",
  username: "tony.stark",
  email: "tony.stark@gmail.com",
  phone: "+1234567890",
  website: "https://github.com/core-ts",
  dateOfBirth: new Date("1963-03-25"),
  creditLimit: 100000.25,
  status: ["active", "online"],
}
errors = validate(user, userSchema, resource, true)
console.log("Validate Tony Stark (no error): ", errors) // should be empty

Out put is:

Validate James Howlett:  [
  {
    field: 'id',
    code: 'maxlength',
    message: 'id cannot be greater than 40 characters.',
    param: 40
  },
  {
    field: 'email',
    code: 'email',
    message: 'Email is not a valid email address.'
  },
  {
    field: 'phone',
    code: 'phone',
    message: 'Telephone is not a valid phone number.'
  },
  { field: 'ip', code: 'ipv4', message: 'ip is not a valid ipv4.' },
  {
    field: 'website',
    code: 'url',
    message: 'Website is not a valid URL.'
  },
  {
    field: 'creditLimit',
    code: 'scale',
    message: 'Credit Limit has a valid scale. Scale must be less than or equal to 2'
  },
  {
    field: 'creditLimit',
    code: 'max',
    message: 'Credit Limit must be less than or equal to 200000.',
    param: 200000
  },
  {
    field: 'status',
    code: 'enum',
    message: 'User Status must be one of active, inactive, online, offline, away.',
    param: 'active, inactive, online, offline, away'
  },
  {
    field: 'age',
    code: 'undefined',
    message: 'age is not allowed to exist.'
  },
  {
    field: 'username',
    code: 'required',
    message: 'Username is required.'
  }
]
Validate Tony Stark (no error):  []

Sample 2

import { Attributes, StringMap, validate } from "xvalidators"

interface Resources {
  [key: string]: StringMap
}

const enResource: StringMap = {
  error_undefined: "{0} is not allowed to exist.",
  error_exp: "{0} does not match the regular expression.",
  error_type: "Invalid datatype. Type of {0} cannot be {1}.",

  error_boolean: "{0} cannot be boolean.",
  error_strings: "{0} must be an string array.",
  error_numbers: "{0} must be an number array.",
  error_integers: "{0} must be an number array.",
  error_datetimes: "{0} must be an date time array.",
  error_dates: "{0} must be an date array.",

  error_required: "{0} is required.",
  error_minlength: "{0} cannot be less than {1} characters.",
  error_maxlength: "{0} cannot be greater than {1} characters.",
  error_array_min: "Length of {0} cannot be less than {1}.",
  error_array_max: "Length of {0} cannot be greater than {1}.",

  error_email: "{0} is not a valid email address.",
  error_integer: "{0} is not a valid integer.",
  error_number: "{0} is not a valid number.",
  error_precision: "{0} has a valid precision. Precision must be less than or equal to {1}",
  error_scale: "{0} has a valid scale. Scale must be less than or equal to {1}",
  error_phone: "{0} is not a valid phone number.",
  error_fax: "{0} is not a valid fax number.",
  error_url: "{0} is not a valid URL.",
  error_ipv4: "{0} is not a valid ipv4.",
  error_ipv6: "{0} is not a valid ipv6.",

  error_min: "{0} must be greater than or equal to {1}.",
  error_max: "{0} must be less than or equal to {1}.",
  error_gt: "{0} must be greater than {1}.",
  error_lt: "{0} must be less than {1}.",
  error_date: "{0} is not a valid date.",
  error_enum: "{0} must be one of {1}.",

  date_of_birth: "Date Of Birth",
  telephone: "Telephone",
  email: "Email",
  website: "Website",
  status: "User Status",
  state: "State",
  zip: "Zip Code",
  zip_code: "Zip code is not valid.",
  quality: "Quality",
  level: "Level",
}

const viResource = {
  error_undefined: "{0} không được phép tồn tại.",
  error_exp: "{0} không khớp với biểu thức chính quy.",
  error_type: "Kiểu dữ liệu không hợp lệ. Kiểu của {0} không thể là {1}.",

  error_boolean: "{0} không thể là kiểu boolean.",
  error_strings: "{0} phải là một mảng chuỗi.",
  error_numbers: "{0} phải là một mảng số.",
  error_integers: "{0} phải là một mảng số nguyên.",
  error_datetimes: "{0} phải là một mảng ngày giờ.",
  error_dates: "{0} phải là một mảng ngày.",

  error_required: "{0} là bắt buộc.",
  error_minlength: "{0} không được ít hơn {1} ký tự.",
  error_maxlength: "{0} không được nhiều hơn {1} ký tự.",
  error_array_min: "Độ dài của {0} không được nhỏ hơn {1}.",
  error_array_max: "Độ dài của {0} không được lớn hơn {1}.",

  error_email: "{0} không phải là địa chỉ email hợp lệ.",
  error_integer: "{0} không phải là số nguyên hợp lệ.",
  error_number: "{0} không phải là số hợp lệ.",
  error_precision: "{0} có độ chính xác không hợp lệ. Độ chính xác phải nhỏ hơn hoặc bằng {1}.",
  error_scale: "{0} có thang đo không hợp lệ. Thang đo phải nhỏ hơn hoặc bằng {1}.",
  error_phone: "{0} không phải là số điện thoại hợp lệ.",
  error_fax: "{0} không phải là số fax hợp lệ.",
  error_url: "{0} không phải là URL hợp lệ.",
  error_ipv4: "{0} không phải là địa chỉ IPv4 hợp lệ.",
  error_ipv6: "{0} không phải là địa chỉ IPv6 hợp lệ.",

  error_min: "{0} phải lớn hơn hoặc bằng {1}.",
  error_max: "{0} phải nhỏ hơn hoặc bằng {1}.",
  error_gt: "{0} phải lớn hơn {1}.",
  error_lt: "{0} phải nhỏ hơn {1}.",
  error_date: "{0} không phải là ngày hợp lệ.",
  error_enum: "{0} phải là một trong các giá trị sau: {1}.",

  date_of_birth: "Ngày sinh",
  telephone: "Điện thoại",
  email: "Địa chỉ email",
  website: "Trang web",
  status: "Trạng thái người dùng",
  state: "Tiểu bang",
  zip: "Mã bưu điện",
  zip_code: "Mã bưu điện không hợp lệ.",
  quality: "Chất lượng",
  level: "Cấp độ",
}

const resources: Resources = {
  en: enResource,
  vi: viResource,
}

function getResource(lang: string): StringMap {
  return resources[lang] || resources["en"]
}
const resource = getResource("en")

interface Skill {
  skill: string
  level: number
}
interface Achievement {
  subject: string
  description: string
  quality: string
  skills?: Skill[]
}
interface Address {
  street: string
  city: string
  state: string
  zip: string
}
interface User {
  id: string
  username: string
  email?: string
  phone?: string
  dateOfBirth?: Date
  website?: string
  creditLimit?: number
  status?: string[]
  address?: Address
  achievements?: Achievement[]
}

const skillSchema: Attributes = {
  skill: {
    required: true,
    length: 15,
  },
  level: {
    required: true,
    type: "integer",
    enum: [1, 2, 3, 4, 5],
    resource: "level",
  },
}
const achievementSchema: Attributes = {
  subject: {
    required: true,
    length: 255,
  },
  description: {
    required: true,
    length: 255,
  },
  quality: {
    required: true,
    length: 255,
    enum: ["Excellent", "Good", "Average", "Poor", "Very Poor"],
    resource: "quality",
  },
  skills: {
    type: "array",
    typeof: skillSchema,
  },
}

const addressSchema: Attributes = {
  street: {
    required: true,
    length: 255,
  },
  city: {
    required: true,
    length: 255,
  },
  state: {
    length: 2,
    exp: /^[A-Z]{2}$/,
    // resource: "State is not valid.",
  },
  zip: {
    exp: /(^\d{5}$)|(^\d{5}-\d{4}$)/,
    resource: "zip_code",
  },
}
const userSchema: Attributes = {
  id: {
    length: 40,
  },
  username: {
    required: true,
    length: 255,
  },
  email: {
    format: "email",
    required: true,
    length: 120,
    resource: "email",
  },
  phone: {
    format: "phone",
    required: true,
    length: 14,
    resource: "telephone",
  },
  website: {
    length: 255,
    format: "url",
    resource: "website",
  },
  dateOfBirth: {
    type: "datetime",
  },
  creditLimit: {
    type: "number",
    precision: 10,
    scale: 2,
    min: 1,
  },
  status: {
    type: "strings",
    enum: ["active", "inactive", "online", "offline", "away"],
    resource: "status",
  },
  address: {
    type: "object",
    typeof: addressSchema,
  },
  achievements: {
    type: "array",
    typeof: achievementSchema,
  },
}

let errors = validate(
  {
    username: "james.howlett",
    email: "james.howlett@gmail", // invalid email
    phone: "", // required => invalid
    website: "https://james.howlett.com",
    dateOfBirth: "1974-03-25", // valid date => the library will convert to date
    age: 50, // does not exist in schema => invalid
  },
  userSchema,
  resource,
)
console.log("Validate James Howlett: ", errors)

const user: User = {
  id: "1234567890123456789012345678901234567890",
  username: "tony.stark",
  email: "tony.stark@gmail.com",
  phone: "+1234567890",
  website: "https://github.com/core-ts",
  dateOfBirth: new Date("1963-03-25"),
  creditLimit: 100000.25,
  status: ["active", "online"],
  address: {
    street: "123 Stark Tower",
    city: "New York",
    state: "NY",
    zip: "07008",
  },
  achievements: [
    {
      subject: "Avengers",
      description: "Leader of the Avengers team",
      quality: "Excellent",
      skills: [
        {
          skill: "Leadership",
          level: 5,
        },
        {
          skill: "Technology",
          level: 4,
        },
        {
          skill: "Martial Arts",
          level: 3,
        },
      ],
    },
    {
      subject: "Iron Suite",
      description: "Iron Armor Suit",
      quality: "Excellent",
    },
  ],
}
errors = validate(user, userSchema, resource, true)
console.log("Validate Tony Stark (no error): ", errors) // should be empty

const invalidUser: User = {
  id: "12345678901234567890123456789012345678901", // 41 characters => maximum 40 => invalid
  username: "peter.parker",
  email: "test", // invalid email
  phone: "abcd1234", // invalid phone number
  website: "wrong url", // invalid URL
  dateOfBirth: new Date("1962-08-25"),
  creditLimit: 10000000.255, // invalid precision and scale => precision must be less than or equal to 10 digits
  status: ["active", "busy"],
  address: {
    street: "123 Stark Tower",
    city: "New York",
    state: "New York",
    zip: "999999", // invalid zip code, does not match regex
  },
  achievements: [
    {
      subject: "Avengers",
      description: "Member of the Avengers team",
      quality: "Normal", // invalid quality, must be one of ["Excellent", "Good", "Average", "Poor", "Very Poor"]
      skills: [
        {
          skill: "Technology",
          level: 5,
        },
        {
          skill: "Martial Arts",
          level: 6, // invalid level, must be be one of [1, 2, 3, 4, 5]
        },
      ],
    },
  ],
}

errors = validate(invalidUser, userSchema, resource, true)
console.log("Validate Peter Parker: ", errors)

Out put is:

Validate James Howlett:  [
  {
    field: 'email',
    code: 'email',
    message: 'Email is not a valid email address.'
  },
  {
    field: 'phone',
    code: 'required',
    message: 'Telephone is required.'
  },
  {
    field: 'age',
    code: 'undefined',
    message: 'age is not allowed to exist.'
  }
]
Validate Tony Stark (no error):  []
Validate Peter Parker:  [
  {
    field: 'id',
    code: 'maxlength',
    message: 'id cannot be greater than 40 characters.',
    param: 40
  },
  {
    field: 'email',
    code: 'email',
    message: 'Email is not a valid email address.'
  },
  {
    field: 'phone',
    code: 'phone',
    message: 'Telephone is not a valid phone number.'
  },
  {
    field: 'website',
    code: 'url',
    message: 'Website is not a valid URL.'
  },
  {
    field: 'creditLimit',
    code: 'precision',
    message: 'creditLimit has a valid precision. Precision must be less than or equal to 10'
  },
  {
    field: 'status',
    code: 'enum',
    message: 'User Status must be one of active, inactive, online, offline, away.',
    param: 'active, inactive, online, offline, away'
  },
  {
    field: 'address.state',
    code: 'maxlength',
    message: 'state cannot be greater than 2 characters.',
    param: 2
  },
  {
    field: 'address.state',
    code: 'exp',
    message: 'state does not match the regular expression.'
  },
  { field: 'address.zip', code: 'exp', message: 'zip_code' },
  {
    field: 'achievements[0].quality',
    code: 'enum',
    message: 'Quality must be one of Excellent, Good, Average, Poor, Very Poor.',
    param: 'Excellent, Good, Average, Poor, Very Poor'
  },
  {
    field: 'achievements[0].skills[1].level',
    code: 'enum',
    message: 'Level must be one of 1, 2, 3, 4, 5.',
    param: '1, 2, 3, 4, 5'
  }
]