A lightweight, dependency-free schema validation library for TypeScript and JavaScript.
Unlike decorator-based or fluent API validators, this library validates plain JavaScript objects using a declarative schema definition. It supports nested objects, arrays, custom validation rules, localization, and asynchronous validation.
- 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.
| 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 | ||
| ✅ 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 ✅ |
- 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)
npm install validation-coreor
yarn add validation-coreimport { validate, Attributes } from "validation-core"
const User: Attributes = {
id: {
type: "ObjectId",
required: true
},
name: {
type: "string",
required: true,
length: 100
},
age: {
type: "integer",
min: 18,
max: 65
},
email: {
type: "string",
format: "email"
}
}
const obj = {
id: "507f1f77bcf86cd799439011",
name: "John",
age: 30,
email: "john@example.com"
}
const errors = validate(obj, User)
console.log(errors)If validation succeeds:
[]Otherwise:
[
{
field: "email",
code: "email",
message: "Email is invalid"
}
]A schema consists of an Attributes object.
const Product: Attributes = {
id: {
type: "string",
required: true
},
price: {
type: "number",
min: 0
}
}| Type | Description |
|---|---|
| ObjectId | MongoDB ObjectId string |
| string | String |
| text | Long text |
| integer | Integer number |
| number | Decimal number |
| boolean | Boolean |
| date | Date only |
| datetime | Date & time |
| time | Time |
| object | Nested object |
| array | Array of objects |
| strings | Array of strings |
| numbers | Array of numbers |
| integers | Array of integers |
| dates | Array of dates |
| datetimes | Array of datetimes |
| primitives | Array of primitive values |
| binary | Binary data |
username: {
type: "string",
required: true,
min: 3,
length: 50
}Supports
- required
- minimum length
- maximum length
- regex
- enum
- format
price: {
type: "number",
min: 0,
max: 1000,
precision: 8,
scale: 2
}Supports
- min
- max
- gt
- lt
- precision
- scale
status: {
type: "string",
enum: [
"NEW",
"ACTIVE",
"DISABLED"
]
}birthday: {
type: "date",
min: "1900-01-01"
}
appointment: {
type: "datetime",
min: "today"
}Supported keywords
- today
- tomorrow
- yesterday
- now
email: {
type: "string",
format: "email"
}Available formats
| Format |
|---|
| url |
| phone |
| fax |
| ipv4 |
| ipv6 |
zipcode: {
type: "string",
exp: /^[0-9]{5}$/
}or
zipcode: {
type: "string",
exp: "^[0-9]{5}$"
}const Address = {
street: {
type: "string",
required: true
},
city: {
type: "string"
}
}
const User = {
name: {
type: "string"
},
address: {
type: "object",
typeof: Address
}
}Validation is recursive.
Array of objects
orders: {
type: "array",
typeof: Order
}Array of strings
tags: {
type: "strings"
}Array of numbers
scores: {
type: "numbers"
}Array of integers
ids: {
type: "integers"
}When validating HTTP PATCH requests, required fields can be ignored.
validate(
obj,
UserSchema,
undefined,
false,
true
)or
check(
obj,
UserSchema,
undefined,
true
)Validation messages are generated from a resource map.
Example:
const resources = {
error_required: "{0} is required",
error_email: "{0} is not a valid email"
}Produces
Email is required
Email is not a valid email
Supports parameter substitution.
"{0} must be greater than {1}"
becomes
Age must be greater than 18
Instead of calling validate() directly, a reusable validator can be created.
const validator = createValidator(User)
const errors = await validator.validate(user)Useful in dependency injection or service layers.
interface ErrorMessage {
field: string
code: string
param?: any
message?: string
}Example
[
{
"field": "age",
"code": "min",
"param": 18,
"message": "Age must be greater than 18"
}
]The library also exposes useful helpers.
isEmail()
isPhone()
isIPv4()
isIPv6()
isUrl()
formatDate()
trimTime()
addDays()
getToday()This library follows a schema-first design.
Instead of decorators
class User {}or fluent builders
z.object({...})validation rules are defined using plain JavaScript objects.
Advantages include
- framework independent
- serializable schemas
- dynamic schema generation
- recursive validation
- minimal runtime overhead
- suitable for backend services and REST APIs
- REST API validation
- Database model validation
- Configuration validation
- CLI input validation
- JSON payload validation
- Microservices
- Express
- Fastify
- NestJS
- Koa
- Serverless Functions
- Simple Sample: data-validation-sample
- Simple REST API Sample: sql-simple-modular-sample
- Backoffice Web App: backoffice
- React Sample: react-cms-backoffice
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 | validation-core | 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 |
- 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.
- ~4.9x slower than Ajv, but ~1.3x faster than Zod, and even faster than Valibot.
- validation-core 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
- Nearly similar in ops/sec, suggesting similar architecture or design trade-offs.
- Good for TypeScript-first developer experience but noticeably slower than Ajv/validation-core.
- 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.
- Significantly slower, not suited for performance-sensitive applications.
- Useful in some backend contexts (Joi) or form validation (Yup), but not recommended when performance matters.
| Use Case | Library | Reason |
|---|---|---|
| High-throughput backend APIs | Ajv | Fastest JSON Schema validator |
| Minimal frontend apps with type-safe apps and custom rules | validation-core | 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 |
- If you need speed: → Ajv
- If you want typescript + good speed + small: → validation-core
- If you prefer a big community support over speed: → Zod or Valibot
- If you already use Formik or legacy stack: → Yup or Joi
| Feature / Library | Ajv | validation-core | Zod | Valibot | Joi | Yup |
|---|---|---|---|---|---|---|
| Required | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Object / Nested validation | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Array validation | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
✅ 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" |
✅ .ip({ version: ["ipv4"] }) |
|||
| IPv6 check | ✅ format: "ipv6" |
✅ format: "ipv6" |
✅ .ip({ version: ["ipv6"] }) |
|||
| Phone number | ✅ format: "phone" |
.pattern() or .custom() with phone regex |
.matches() with regex |
|||
| Fax number | ✅ format: "fax" |
.pattern() or .custom() with phone regex |
.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) | ✅ scale: n |
.precision() + .max() |
||||
| Date type | ✅ format: "date" / "date-time" |
✅ type: "date" | "datetime" |
✅ z.date() / .datetime() |
✅ date() |
✅ .date() |
✅ .date() |
| Relative date (now/today/tomorrow/yesterday) | ✅ min: "now" | "today" | "tomorrow" | "yesterday" |
.refine() |
.refine() |
✅ .min('now') / .max('now') + Date values |
.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 |
import { Attributes, StringMap, validate } from "validation-core"
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: "/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 emptyOut 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): []
import { Attributes, StringMap, validate } from "validation-core"
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: "/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'
}
]