|
| 1 | +# Validator |
| 2 | + |
| 3 | +<!--introduced_in=vREPLACEME--> |
| 4 | + |
| 5 | +<!-- YAML |
| 6 | +added: REPLACEME |
| 7 | +--> |
| 8 | + |
| 9 | +> Stability: 1.0 - Early development |
| 10 | +
|
| 11 | +> This feature is experimental and may change at any time. To disable it, |
| 12 | +> start Node.js with [`--no-experimental-validator`][]. |
| 13 | +
|
| 14 | +<!-- source_link=lib/validator.js --> |
| 15 | + |
| 16 | +The `node:validator` module provides a schema-based object validator for |
| 17 | +simple REST API input validation. It supports basic type checking, property |
| 18 | +constraints, required fields, and nested schemas. |
| 19 | + |
| 20 | +To access it: |
| 21 | + |
| 22 | +```mjs |
| 23 | +import { Schema } from 'node:validator'; |
| 24 | +``` |
| 25 | + |
| 26 | +```cjs |
| 27 | +const { Schema } = require('node:validator'); |
| 28 | +``` |
| 29 | + |
| 30 | +This module is only available under the `node:` scheme. |
| 31 | + |
| 32 | +The following example shows the basic usage of the `node:validator` module |
| 33 | +to validate a user object. |
| 34 | + |
| 35 | +```mjs |
| 36 | +import { Schema } from 'node:validator'; |
| 37 | + |
| 38 | +const userSchema = new Schema({ |
| 39 | + type: 'object', |
| 40 | + required: ['name', 'email'], |
| 41 | + properties: { |
| 42 | + name: { type: 'string', minLength: 1, maxLength: 100 }, |
| 43 | + email: { type: 'string', pattern: '^[^@]+@[^@]+$' }, |
| 44 | + age: { type: 'integer', minimum: 0, maximum: 150 }, |
| 45 | + tags: { type: 'array', items: { type: 'string' }, maxItems: 10 }, |
| 46 | + }, |
| 47 | +}); |
| 48 | + |
| 49 | +const result = userSchema.validate({ |
| 50 | + name: 'Alice', |
| 51 | + |
| 52 | + age: 30, |
| 53 | + tags: ['admin'], |
| 54 | +}); |
| 55 | + |
| 56 | +console.log(result.valid); // true |
| 57 | +console.log(result.errors); // [] |
| 58 | +``` |
| 59 | + |
| 60 | +```cjs |
| 61 | +'use strict'; |
| 62 | +const { Schema } = require('node:validator'); |
| 63 | + |
| 64 | +const userSchema = new Schema({ |
| 65 | + type: 'object', |
| 66 | + required: ['name', 'email'], |
| 67 | + properties: { |
| 68 | + name: { type: 'string', minLength: 1, maxLength: 100 }, |
| 69 | + email: { type: 'string', pattern: '^[^@]+@[^@]+$' }, |
| 70 | + age: { type: 'integer', minimum: 0, maximum: 150 }, |
| 71 | + tags: { type: 'array', items: { type: 'string' }, maxItems: 10 }, |
| 72 | + }, |
| 73 | +}); |
| 74 | + |
| 75 | +const result = userSchema.validate({ |
| 76 | + name: 'Alice', |
| 77 | + |
| 78 | + age: 30, |
| 79 | + tags: ['admin'], |
| 80 | +}); |
| 81 | + |
| 82 | +console.log(result.valid); // true |
| 83 | +console.log(result.errors); // [] |
| 84 | +``` |
| 85 | + |
| 86 | +## Validation error codes |
| 87 | + |
| 88 | +<!-- YAML |
| 89 | +added: REPLACEME |
| 90 | +--> |
| 91 | + |
| 92 | +The following error codes are returned in the `code` field of validation |
| 93 | +error objects. They are also available as properties of the `codes` export. |
| 94 | + |
| 95 | +| Code | Description | |
| 96 | +| ---- | ----------- | |
| 97 | +| `INVALID_TYPE` | Value type does not match the declared type | |
| 98 | +| `MISSING_REQUIRED` | A required property is missing | |
| 99 | +| `STRING_TOO_SHORT` | String is shorter than `minLength` | |
| 100 | +| `STRING_TOO_LONG` | String is longer than `maxLength` | |
| 101 | +| `PATTERN_MISMATCH` | String does not match the `pattern` regex | |
| 102 | +| `ENUM_MISMATCH` | Value is not one of the allowed `enum` values | |
| 103 | +| `NUMBER_TOO_SMALL` | Number is below `minimum` or `exclusiveMinimum` | |
| 104 | +| `NUMBER_TOO_LARGE` | Number is above `maximum` or `exclusiveMaximum` | |
| 105 | +| `NUMBER_NOT_MULTIPLE` | Number is not a multiple of `multipleOf` | |
| 106 | +| `NOT_INTEGER` | Value is not an integer when `type` is `'integer'` | |
| 107 | +| `ARRAY_TOO_SHORT` | Array has fewer items than `minItems` | |
| 108 | +| `ARRAY_TOO_LONG` | Array has more items than `maxItems` | |
| 109 | +| `ADDITIONAL_PROPERTY` | Object has a property not listed in `properties` when `additionalProperties` is `false` | |
| 110 | + |
| 111 | +Compare the `code` field of a validation error against the `codes` export |
| 112 | +instead of hard-coding string literals: |
| 113 | + |
| 114 | +```cjs |
| 115 | +const { Schema, codes } = require('node:validator'); |
| 116 | + |
| 117 | +const schema = new Schema({ type: 'number', minimum: 0 }); |
| 118 | +const result = schema.validate(-1); |
| 119 | +if (!result.valid && result.errors[0].code === codes.NUMBER_TOO_SMALL) { |
| 120 | + // Handle the below-minimum case. |
| 121 | +} |
| 122 | +``` |
| 123 | + |
| 124 | +## Class: `Schema` |
| 125 | + |
| 126 | +<!-- YAML |
| 127 | +added: REPLACEME |
| 128 | +--> |
| 129 | + |
| 130 | +### `new Schema(definition)` |
| 131 | + |
| 132 | +<!-- YAML |
| 133 | +added: REPLACEME |
| 134 | +--> |
| 135 | + |
| 136 | +* `definition` {Object} A schema definition object. |
| 137 | + |
| 138 | +Creates a new `Schema` instance. The schema definition is validated and |
| 139 | +compiled at construction time. [`ERR_VALIDATOR_INVALID_SCHEMA`][] is thrown |
| 140 | +if the definition is invalid. |
| 141 | + |
| 142 | +The `definition` object must have a `type` property set to one of the |
| 143 | +supported types: `'string'`, `'number'`, `'integer'`, `'boolean'`, |
| 144 | +`'object'`, `'array'`, or `'null'`. |
| 145 | + |
| 146 | +#### Schema definition properties |
| 147 | + |
| 148 | +The following properties are supported depending on the schema type. |
| 149 | + |
| 150 | +##### All types |
| 151 | + |
| 152 | +* `type` {string} **Required.** One of `'string'`, `'number'`, `'integer'`, |
| 153 | + `'boolean'`, `'object'`, `'array'`, `'null'`. |
| 154 | +* `default` {any} Default value to apply when using |
| 155 | + [`schema.applyDefaults()`][]. |
| 156 | + |
| 157 | +##### Type: `'string'` |
| 158 | + |
| 159 | +* `minLength` {number} Minimum string length (inclusive). Must be a |
| 160 | + non-negative integer. |
| 161 | +* `maxLength` {number} Maximum string length (inclusive). Must be a |
| 162 | + non-negative integer. |
| 163 | +* `pattern` {string} A regular expression pattern the string must match. |
| 164 | +* `enum` {Array} An array of allowed values. |
| 165 | + |
| 166 | +##### Type: `'number'` |
| 167 | + |
| 168 | +* `minimum` {number} Minimum value (inclusive). |
| 169 | +* `maximum` {number} Maximum value (inclusive). |
| 170 | +* `exclusiveMinimum` {number} Minimum value (exclusive). |
| 171 | +* `exclusiveMaximum` {number} Maximum value (exclusive). |
| 172 | +* `multipleOf` {number} The value must be a multiple of this number. Must be |
| 173 | + greater than 0. |
| 174 | + |
| 175 | +##### Type: `'integer'` |
| 176 | + |
| 177 | +Same constraints as `'number'`. Additionally, the value must be an integer. |
| 178 | + |
| 179 | +##### Type: `'array'` |
| 180 | + |
| 181 | +* `items` {Object} A schema definition for array elements. |
| 182 | +* `minItems` {number} Minimum array length (inclusive). Must be a |
| 183 | + non-negative integer. |
| 184 | +* `maxItems` {number} Maximum array length (inclusive). Must be a |
| 185 | + non-negative integer. |
| 186 | + |
| 187 | +##### Type: `'object'` |
| 188 | + |
| 189 | +* `properties` {Object} A map of property names to schema definitions. |
| 190 | +* `required` {string\[]} An array of required property names. Each name must |
| 191 | + be defined in `properties`. |
| 192 | +* `additionalProperties` {boolean} Whether properties not listed in |
| 193 | + `properties` are allowed. **Default:** `true`. |
| 194 | + |
| 195 | +### `schema.validate(data)` |
| 196 | + |
| 197 | +<!-- YAML |
| 198 | +added: REPLACEME |
| 199 | +--> |
| 200 | + |
| 201 | +* `data` {any} The value to validate. |
| 202 | +* Returns: {ValidationResult} |
| 203 | + |
| 204 | +Validates the given data against the schema. Returns a frozen object with |
| 205 | +`valid` and `errors` properties. Validation never throws; all validation |
| 206 | +failures are returned in the `errors` array. |
| 207 | + |
| 208 | +```cjs |
| 209 | +const { Schema } = require('node:validator'); |
| 210 | +const schema = new Schema({ type: 'string', minLength: 1 }); |
| 211 | + |
| 212 | +const good = schema.validate('hello'); |
| 213 | +console.log(good.valid); // true |
| 214 | + |
| 215 | +const bad = schema.validate(''); |
| 216 | +console.log(bad.valid); // false |
| 217 | +console.log(bad.errors[0].code); // 'STRING_TOO_SHORT' |
| 218 | +``` |
| 219 | + |
| 220 | +### `schema.applyDefaults(data)` |
| 221 | + |
| 222 | +<!-- YAML |
| 223 | +added: REPLACEME |
| 224 | +--> |
| 225 | + |
| 226 | +* `data` {any} The data object to apply defaults to. |
| 227 | +* Returns: {Object} A new object with defaults applied. |
| 228 | + |
| 229 | +Returns a new object with default values applied for missing or `undefined` |
| 230 | +properties. The input data is not mutated. Defaults are applied recursively |
| 231 | +for nested object schemas. |
| 232 | + |
| 233 | +```cjs |
| 234 | +const { Schema } = require('node:validator'); |
| 235 | +const schema = new Schema({ |
| 236 | + type: 'object', |
| 237 | + properties: { |
| 238 | + host: { type: 'string', default: 'localhost' }, |
| 239 | + port: { type: 'integer', default: 3000 }, |
| 240 | + }, |
| 241 | +}); |
| 242 | + |
| 243 | +const config = schema.applyDefaults({}); |
| 244 | +console.log(config.host); // 'localhost' |
| 245 | +console.log(config.port); // 3000 |
| 246 | +``` |
| 247 | + |
| 248 | +### `schema.toJSON()` |
| 249 | + |
| 250 | +<!-- YAML |
| 251 | +added: REPLACEME |
| 252 | +--> |
| 253 | + |
| 254 | +* Returns: {Object} A frozen copy of the original schema definition. |
| 255 | + |
| 256 | +Returns the original schema definition as a frozen plain object. This is |
| 257 | +useful for composing schemas — pass the result as a sub-schema definition |
| 258 | +in another schema: |
| 259 | + |
| 260 | +```cjs |
| 261 | +const { Schema } = require('node:validator'); |
| 262 | +const addressSchema = new Schema({ |
| 263 | + type: 'object', |
| 264 | + properties: { |
| 265 | + street: { type: 'string' }, |
| 266 | + city: { type: 'string' }, |
| 267 | + }, |
| 268 | +}); |
| 269 | + |
| 270 | +const userSchema = new Schema({ |
| 271 | + type: 'object', |
| 272 | + properties: { |
| 273 | + name: { type: 'string' }, |
| 274 | + address: addressSchema.toJSON(), |
| 275 | + }, |
| 276 | +}); |
| 277 | +``` |
| 278 | + |
| 279 | +### Static method: `Schema.validate(definition, data)` |
| 280 | + |
| 281 | +<!-- YAML |
| 282 | +added: REPLACEME |
| 283 | +--> |
| 284 | + |
| 285 | +* `definition` {Object} A schema definition object. |
| 286 | +* `data` {any} The value to validate. |
| 287 | +* Returns: {ValidationResult} |
| 288 | + |
| 289 | +Convenience method that creates a `Schema` and validates in one call. |
| 290 | +Equivalent to `new Schema(definition).validate(data)`. The definition is |
| 291 | +compiled on every invocation; when validating repeatedly against the same |
| 292 | +schema, reuse a single `new Schema()` instance instead. |
| 293 | + |
| 294 | +```cjs |
| 295 | +const { Schema } = require('node:validator'); |
| 296 | +const result = Schema.validate({ type: 'number', minimum: 0 }, 42); |
| 297 | +console.log(result.valid); // true |
| 298 | +``` |
| 299 | + |
| 300 | +## Type: `ValidationResult` |
| 301 | + |
| 302 | +<!-- YAML |
| 303 | +added: REPLACEME |
| 304 | +--> |
| 305 | + |
| 306 | +The object returned by [`schema.validate()`][]. It is a frozen plain object |
| 307 | +with the following properties: |
| 308 | + |
| 309 | +* `valid` {boolean} `true` if the data matches the schema. |
| 310 | +* `errors` {Object\[]} A frozen array of error objects. Empty when `valid` |
| 311 | + is `true`. Each error object has the following properties: |
| 312 | + * `path` {string} The path to the invalid value using dot notation for |
| 313 | + object properties and bracket notation for array indices. The root |
| 314 | + path is an empty string. |
| 315 | + * `message` {string} A human-readable error description. |
| 316 | + * `code` {string} A machine-readable error code from the |
| 317 | + [validation error codes][] table. |
| 318 | + |
| 319 | +[`--no-experimental-validator`]: cli.md#--no-experimental-validator |
| 320 | +[`ERR_VALIDATOR_INVALID_SCHEMA`]: errors.md#err_validator_invalid_schema |
| 321 | +[`schema.applyDefaults()`]: #schemaapplydefaultsdata |
| 322 | +[`schema.validate()`]: #schemavalidatedata |
| 323 | +[validation error codes]: #validation-error-codes |
0 commit comments