0
# Validation
1
2
Comprehensive validation system supporting object validation, MongoDB modifiers, custom validators, and detailed error reporting.
3
4
## Capabilities
5
6
### Object Validation
7
8
Primary validation method that throws errors on validation failure.
9
10
```typescript { .api }
11
/**
12
* Validates an object against the schema, throwing an error if validation fails
13
* @param obj - Object to validate
14
* @param options - Validation options
15
* @throws ValidationError if validation fails
16
*/
17
validate(obj: any, options?: ValidationOptions): void;
18
19
interface ValidationOptions {
20
/** Extended custom context for validation functions */
21
extendedCustomContext?: Record<string | number | symbol, unknown>;
22
/** Array of field keys to ignore during validation */
23
ignore?: string[];
24
/** Array of field keys to validate (validates only these keys) */
25
keys?: string[];
26
/** Whether to validate as MongoDB modifier document */
27
modifier?: boolean;
28
/** MongoObject instance for modifier validation */
29
mongoObject?: any;
30
/** Whether this is an upsert operation */
31
upsert?: boolean;
32
}
33
```
34
35
**Usage Examples:**
36
37
```typescript
38
import SimpleSchema from "simpl-schema";
39
40
const userSchema = new SimpleSchema({
41
name: String,
42
email: String,
43
age: Number
44
});
45
46
// Basic validation - throws on error
47
try {
48
userSchema.validate({ name: "John", email: "john@example.com", age: 25 });
49
console.log("Valid!");
50
} catch (error) {
51
console.log("Validation failed:", error.message);
52
}
53
54
// Validate specific keys only
55
userSchema.validate(
56
{ name: "John", age: 25 },
57
{ keys: ['name', 'age'] }
58
);
59
60
// Validate MongoDB modifier document
61
userSchema.validate(
62
{ $set: { name: "John Doe" } },
63
{ modifier: true }
64
);
65
```
66
67
### Static Validation
68
69
Class-level validation method for one-off validations without creating schema instances.
70
71
```typescript { .api }
72
/**
73
* Static validation method for validating against schema definitions
74
* @param obj - Object to validate
75
* @param schema - Schema instance or definition to validate against
76
* @param options - Validation options
77
* @throws ValidationError if validation fails
78
*/
79
static validate(obj: any, schema: SimpleSchema | SchemaDefinition, options?: ValidationOptions): void;
80
```
81
82
**Usage Examples:**
83
84
```typescript
85
// Validate against schema definition directly
86
SimpleSchema.validate(
87
{ name: "John", age: 25 },
88
{ name: String, age: Number }
89
);
90
91
// Validate against existing schema
92
const userSchema = new SimpleSchema({ name: String, age: Number });
93
SimpleSchema.validate({ name: "John", age: 25 }, userSchema);
94
```
95
96
### Async Validation
97
98
Async validation method that returns validation errors as a promise instead of throwing.
99
100
```typescript { .api }
101
/**
102
* Validates an object and returns validation errors as a promise
103
* @param obj - Object to validate
104
* @param options - Validation options
105
* @returns Promise that resolves to array of validation errors
106
*/
107
async validateAndReturnErrorsPromise(obj: any, options: ValidationOptions): Promise<ValidationError[]>;
108
```
109
110
**Usage Examples:**
111
112
```typescript
113
const userSchema = new SimpleSchema({
114
name: { type: String, min: 2 },
115
email: { type: String, regEx: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ },
116
age: { type: Number, min: 0 }
117
});
118
119
// Async validation that returns errors instead of throwing
120
const errors = await userSchema.validateAndReturnErrorsPromise({
121
name: "J", // Too short
122
email: "invalid", // Invalid format
123
age: -5 // Below minimum
124
});
125
126
console.log(errors);
127
// [
128
// { name: 'name', type: 'minString', value: 'J', message: 'Name must be at least 2 characters' },
129
// { name: 'email', type: 'regEx', value: 'invalid', message: 'Email failed regular expression validation' },
130
// { name: 'age', type: 'minNumber', value: -5, message: 'Age must be at least 0' }
131
// ]
132
133
// Handle validation in async context
134
try {
135
const validationErrors = await userSchema.validateAndReturnErrorsPromise(userData);
136
if (validationErrors.length > 0) {
137
// Handle validation errors
138
validationErrors.forEach(error => {
139
console.log(`Field ${error.name}: ${error.message}`);
140
});
141
} else {
142
console.log('Validation passed!');
143
}
144
} catch (error) {
145
console.log('Validation system error:', error);
146
}
147
```
148
149
### Validator Functions
150
151
Create reusable validator functions for repeated validation scenarios.
152
153
```typescript { .api }
154
/**
155
* Returns a validator function that can be called repeatedly
156
* @param options - Validation options with additional configuration
157
* @returns Function that validates objects and returns boolean or throws
158
*/
159
validator(options?: ValidationOptions & {
160
clean?: boolean;
161
returnErrorsPromise?: boolean;
162
}): Function;
163
164
/**
165
* Returns a form-specific validator function that returns errors as a promise
166
* @param options - Form validation options
167
* @returns Function that validates and returns promise with validation errors
168
*/
169
getFormValidator(options?: ValidationOptions): (obj: Record<string, any>) => Promise<ValidationError[]>;
170
```
171
172
**Usage Examples:**
173
174
```typescript
175
const userSchema = new SimpleSchema({
176
name: String,
177
email: String
178
});
179
180
// Create validator that throws on error
181
const validateUser = userSchema.validator();
182
validateUser({ name: "John", email: "john@example.com" });
183
184
// Create validator that cleans before validating
185
const cleanAndValidate = userSchema.validator({ clean: true });
186
187
// Create validator that returns promise with errors
188
const asyncValidator = userSchema.validator({ returnErrorsPromise: true });
189
asyncValidator(userData).then(errors => {
190
if (errors.length > 0) {
191
console.log("Validation errors:", errors);
192
}
193
});
194
195
// Create form validator (always returns promise with errors)
196
const formValidator = userSchema.getFormValidator();
197
formValidator(formData).then(errors => {
198
if (errors.length > 0) {
199
// Display form errors to user
200
errors.forEach(error => {
201
displayFieldError(error.name, error.message);
202
});
203
} else {
204
// Submit form
205
submitForm(formData);
206
}
207
});
208
```
209
210
### Validation Contexts
211
212
Create validation contexts for collecting errors without throwing exceptions.
213
214
```typescript { .api }
215
/**
216
* Creates a new validation context for this schema
217
* @returns New ValidationContext instance
218
*/
219
newContext(): ValidationContext;
220
221
/**
222
* Gets or creates a named validation context
223
* @param name - Context name for reuse
224
* @returns Named ValidationContext instance
225
*/
226
namedContext(name?: string): ValidationContext;
227
```
228
229
**Usage Examples:**
230
231
```typescript
232
const userSchema = new SimpleSchema({
233
name: String,
234
email: String
235
});
236
237
// Create new context
238
const context = userSchema.newContext();
239
const isValid = context.validate({ name: "John" }); // false
240
if (!isValid) {
241
console.log(context.validationErrors()); // Array of errors
242
}
243
244
// Use named context for persistence
245
const formContext = userSchema.namedContext('userForm');
246
formContext.validate(formData);
247
// Later, reuse the same context
248
const sameContext = userSchema.namedContext('userForm');
249
console.log(sameContext.validationErrors());
250
```
251
252
### Custom Validators
253
254
Add custom validation logic at the schema or field level.
255
256
```typescript { .api }
257
/**
258
* Adds a custom validator function to this schema instance
259
* @param func - Validator function to add
260
*/
261
addValidator(func: ValidatorFunction): void;
262
263
/**
264
* Adds a document-level validator function to this schema instance
265
* @param func - Document validator function to add
266
*/
267
addDocValidator(func: DocValidatorFunction): void;
268
269
/**
270
* Adds a custom validator function globally to all schema instances
271
* @param func - Validator function to add globally
272
*/
273
static addValidator(func: ValidatorFunction): void;
274
275
/**
276
* Adds a document-level validator function globally to all schema instances
277
* @param func - Document validator function to add globally
278
*/
279
static addDocValidator(func: DocValidatorFunction): void;
280
281
// Validator function types
282
type ValidatorFunction = (this: ValidatorContext) => void | undefined | boolean | string | ValidationErrorResult;
283
type DocValidatorFunction = (this: DocValidatorContext, obj: Record<string, unknown>) => ValidationError[];
284
285
interface ValidatorContext {
286
key: string;
287
keyPath: string;
288
value: any;
289
definition: StandardSchemaKeyDefinitionWithSimpleTypes;
290
isSet: boolean;
291
operator: string | null;
292
validationContext: ValidationContext;
293
field(key: string): FieldInfo<any>;
294
siblingField(key: string): FieldInfo<any>;
295
addValidationErrors(errors: ValidationError[]): void;
296
}
297
```
298
299
**Usage Examples:**
300
301
```typescript
302
// Field-level custom validator
303
const userSchema = new SimpleSchema({
304
email: {
305
type: String,
306
custom() {
307
if (!this.value.includes('@')) {
308
return 'emailInvalid';
309
}
310
}
311
},
312
password: {
313
type: String,
314
min: 8,
315
custom() {
316
if (!/[A-Z]/.test(this.value)) {
317
return 'passwordNeedsUppercase';
318
}
319
}
320
}
321
});
322
323
// Schema-level custom validator
324
userSchema.addValidator(function() {
325
if (this.key === 'confirmPassword') {
326
const password = this.field('password').value;
327
if (password !== this.value) {
328
return 'passwordMismatch';
329
}
330
}
331
});
332
333
// Document-level validator
334
userSchema.addDocValidator(function(obj) {
335
const errors = [];
336
if (obj.age < 18 && obj.hasAccount) {
337
errors.push({
338
name: 'hasAccount',
339
type: 'minorWithAccount',
340
value: obj.hasAccount
341
});
342
}
343
return errors;
344
});
345
346
// Global validator affecting all schemas
347
SimpleSchema.addValidator(function() {
348
if (this.key.endsWith('Email') && this.isSet) {
349
if (!this.value.includes('@')) {
350
return 'mustBeEmail';
351
}
352
}
353
});
354
```
355
356
### MongoDB Modifier Validation
357
358
Validate MongoDB update modifier documents like `$set`, `$unset`, `$push`, etc.
359
360
```typescript { .api }
361
// Enable modifier validation in options
362
interface ValidationOptions {
363
/** Whether to validate as MongoDB modifier document */
364
modifier?: boolean;
365
/** MongoObject instance for advanced modifier validation */
366
mongoObject?: any;
367
/** Whether this is an upsert operation */
368
upsert?: boolean;
369
}
370
```
371
372
**Usage Examples:**
373
374
```typescript
375
const userSchema = new SimpleSchema({
376
'profile.name': String,
377
'profile.age': Number,
378
tags: [String],
379
lastLogin: Date
380
});
381
382
// Validate $set modifier
383
userSchema.validate({
384
$set: {
385
'profile.name': 'John Doe',
386
'profile.age': 30
387
}
388
}, { modifier: true });
389
390
// Validate $push modifier
391
userSchema.validate({
392
$push: {
393
tags: 'javascript'
394
}
395
}, { modifier: true });
396
397
// Validate $unset modifier
398
userSchema.validate({
399
$unset: {
400
'profile.age': ""
401
}
402
}, { modifier: true });
403
404
// Complex modifier with multiple operations
405
userSchema.validate({
406
$set: { 'profile.name': 'Jane Doe' },
407
$push: { tags: 'react' },
408
$currentDate: { lastLogin: true }
409
}, { modifier: true });
410
```
411
412
### Async Validation
413
414
Handle validation operations that return promises for async validation scenarios.
415
416
```typescript { .api }
417
/**
418
* Validates and returns errors as a promise
419
* @param obj - Object to validate
420
* @param options - Validation options
421
* @returns Promise resolving to array of ValidationError objects
422
*/
423
validateAndReturnErrorsPromise(obj: any, options: ValidationOptions): Promise<ValidationError[]>;
424
```
425
426
**Usage Examples:**
427
428
```typescript
429
const userSchema = new SimpleSchema({
430
username: {
431
type: String,
432
custom() {
433
// Simulate async validation (e.g., checking uniqueness)
434
return new Promise((resolve) => {
435
setTimeout(() => {
436
if (this.value === 'admin') {
437
resolve('usernameNotAllowed');
438
} else {
439
resolve();
440
}
441
}, 100);
442
});
443
}
444
}
445
});
446
447
// Use async validation
448
userSchema.validateAndReturnErrorsPromise({ username: 'admin' })
449
.then(errors => {
450
if (errors.length > 0) {
451
console.log('Validation errors:', errors);
452
} else {
453
console.log('Valid!');
454
}
455
});
456
```
457
458
## Types
459
460
```typescript { .api }
461
interface ValidationError {
462
/** Localized error message */
463
message?: string;
464
/** Field name that failed validation */
465
name: string;
466
/** Type of validation error */
467
type: string;
468
/** Value that failed validation */
469
value: any;
470
/** Additional error properties */
471
[prop: string]: any;
472
}
473
474
interface ValidationErrorResult {
475
type: string;
476
value?: any;
477
message?: string;
478
}
479
480
interface FieldInfo<ValueType> {
481
value: ValueType;
482
isSet: boolean;
483
operator: string | null;
484
}
485
```