perfect-payload 1.2.3 → 1.3.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +919 -340
- package/index.js +41 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# perfect-payload
|
|
2
2
|
|
|
3
3
|
A lightweight JavaScript payload validation utility for validating API
|
|
4
|
+
|
|
4
5
|
and JSON payloads with simple rule-based configuration.
|
|
5
6
|
|
|
6
7
|
## Installation
|
|
@@ -8,6 +9,7 @@ and JSON payloads with simple rule-based configuration.
|
|
|
8
9
|
```bash
|
|
9
10
|
|
|
10
11
|
npm install perfect-payload
|
|
12
|
+
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
## Basic Usage
|
|
@@ -19,24 +21,30 @@ import { perfectPayload } from "perfect-payload";
|
|
|
19
21
|
|
|
20
22
|
const payload = {
|
|
21
23
|
name: "Kiran",
|
|
24
|
+
|
|
22
25
|
email: "kiran@example.com",
|
|
26
|
+
|
|
23
27
|
age: 29,
|
|
24
28
|
};
|
|
25
29
|
|
|
26
30
|
const validationRules = {
|
|
27
31
|
name: {
|
|
28
32
|
mandatory: true,
|
|
33
|
+
|
|
29
34
|
type: "string",
|
|
30
35
|
},
|
|
31
36
|
|
|
32
37
|
email: {
|
|
33
38
|
mandatory: true,
|
|
39
|
+
|
|
34
40
|
type: "email",
|
|
35
41
|
},
|
|
36
42
|
|
|
37
43
|
age: {
|
|
38
44
|
mandatory: true,
|
|
45
|
+
|
|
39
46
|
type: "number",
|
|
47
|
+
|
|
40
48
|
min: 18,
|
|
41
49
|
},
|
|
42
50
|
};
|
|
@@ -51,19 +59,31 @@ console.log(result);
|
|
|
51
59
|
```js
|
|
52
60
|
|
|
53
61
|
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
|
|
63
|
+
statusCode: 200,
|
|
64
|
+
|
|
65
|
+
valid: true,
|
|
66
|
+
|
|
67
|
+
validatedPayload: {
|
|
68
|
+
|
|
69
|
+
name: "Kiran",
|
|
70
|
+
|
|
71
|
+
email: "kiran@example.com",
|
|
72
|
+
|
|
73
|
+
age: 29
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
61
77
|
}
|
|
78
|
+
|
|
62
79
|
```
|
|
63
80
|
|
|
64
81
|
**Note:** The validatedPayload contains only the fields defined in the
|
|
82
|
+
|
|
65
83
|
schema, automatically filtering out any extra attributes. You can use it
|
|
84
|
+
|
|
66
85
|
to safely overwrite request.body or assign it to a new request property
|
|
86
|
+
|
|
67
87
|
(such as validatedBody, sanitisedData or parsedBody).
|
|
68
88
|
|
|
69
89
|
### Invalid Response
|
|
@@ -71,17 +91,29 @@ to safely overwrite request.body or assign it to a new request property
|
|
|
71
91
|
```js
|
|
72
92
|
|
|
73
93
|
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
|
|
95
|
+
statusCode: 400,
|
|
96
|
+
|
|
97
|
+
valid: false,
|
|
98
|
+
|
|
99
|
+
message: "One or more attribute values are invalid",
|
|
100
|
+
|
|
101
|
+
errors: [
|
|
102
|
+
|
|
103
|
+
{
|
|
104
|
+
|
|
105
|
+
path: "email",
|
|
106
|
+
|
|
107
|
+
code: "INVALID_EMAIL",
|
|
108
|
+
|
|
109
|
+
message: "Invalid email format for attribute email"
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
]
|
|
114
|
+
|
|
84
115
|
}
|
|
116
|
+
|
|
85
117
|
```
|
|
86
118
|
|
|
87
119
|
Each error returned by `perfectPayload()` contains:
|
|
@@ -89,17 +121,26 @@ Each error returned by `perfectPayload()` contains:
|
|
|
89
121
|
```js
|
|
90
122
|
|
|
91
123
|
{
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
124
|
+
|
|
125
|
+
path: "field.path",
|
|
126
|
+
|
|
127
|
+
code: "ERROR_CODE",
|
|
128
|
+
|
|
129
|
+
message: "Human readable validation message"
|
|
130
|
+
|
|
95
131
|
}
|
|
132
|
+
|
|
96
133
|
```
|
|
97
134
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
135
|
+
\- `path` identifies the exact field that failed validation.
|
|
136
|
+
|
|
137
|
+
\- `code` provides a stable machine-readable validation error code.
|
|
138
|
+
|
|
139
|
+
\- `message` provides a human-readable description of the validation
|
|
140
|
+
|
|
141
|
+
failure.
|
|
142
|
+
|
|
143
|
+
\- Submitted payload values are not included in default error messages.
|
|
103
144
|
|
|
104
145
|
## Legacy API
|
|
105
146
|
|
|
@@ -110,9 +151,11 @@ import { perfectPayloadV1 } from "perfect-payload";
|
|
|
110
151
|
```
|
|
111
152
|
|
|
112
153
|
`perfectPayloadV1()` is deprecated and will no longer be supported after
|
|
113
|
-
|
|
154
|
+
|
|
155
|
+
**March 31, 2027**.
|
|
114
156
|
|
|
115
157
|
Existing applications can continue using it during the migration period,
|
|
158
|
+
|
|
116
159
|
but all new implementations should use:
|
|
117
160
|
|
|
118
161
|
```js
|
|
@@ -131,15 +174,20 @@ while the new `perfectPayload()` API returns structured errors:
|
|
|
131
174
|
errors: [
|
|
132
175
|
{
|
|
133
176
|
path: "email",
|
|
177
|
+
|
|
134
178
|
code: "INVALID_EMAIL",
|
|
179
|
+
|
|
135
180
|
message: "Invalid email format for attribute email",
|
|
136
181
|
},
|
|
137
182
|
];
|
|
138
183
|
```
|
|
139
184
|
|
|
140
185
|
**Note:** If an inValidPayloadResponse is provided, the system returns
|
|
186
|
+
|
|
141
187
|
it alongside an automatically generated errors property. Do not include
|
|
188
|
+
|
|
142
189
|
your own errors attribute inside the custom inValidPayloadResponse
|
|
190
|
+
|
|
143
191
|
object.
|
|
144
192
|
|
|
145
193
|
## Validation Rules
|
|
@@ -162,7 +210,7 @@ const rules = {
|
|
|
162
210
|
|
|
163
211
|
Error code: `REQUIRED`
|
|
164
212
|
|
|
165
|
-
|
|
213
|
+
**---**
|
|
166
214
|
|
|
167
215
|
### `allowNull`
|
|
168
216
|
|
|
@@ -182,7 +230,7 @@ const rules = {
|
|
|
182
230
|
|
|
183
231
|
Error code: `NULL_NOT_ALLOWED`
|
|
184
232
|
|
|
185
|
-
|
|
233
|
+
**---**
|
|
186
234
|
|
|
187
235
|
### `allowEmptyObject`
|
|
188
236
|
|
|
@@ -196,6 +244,7 @@ Example:
|
|
|
196
244
|
const rules = {
|
|
197
245
|
address: {
|
|
198
246
|
type: "object",
|
|
247
|
+
|
|
199
248
|
allowEmptyObject: false,
|
|
200
249
|
},
|
|
201
250
|
};
|
|
@@ -203,7 +252,7 @@ const rules = {
|
|
|
203
252
|
|
|
204
253
|
Error code: `EMPTY_OBJECT_NOT_ALLOWED`
|
|
205
254
|
|
|
206
|
-
|
|
255
|
+
**---**
|
|
207
256
|
|
|
208
257
|
### `allowEmptyArray`
|
|
209
258
|
|
|
@@ -217,6 +266,7 @@ Example:
|
|
|
217
266
|
const rules = {
|
|
218
267
|
products: {
|
|
219
268
|
type: "array",
|
|
269
|
+
|
|
220
270
|
allowEmptyArray: false,
|
|
221
271
|
},
|
|
222
272
|
};
|
|
@@ -224,7 +274,7 @@ const rules = {
|
|
|
224
274
|
|
|
225
275
|
Error code: `EMPTY_ARRAY_NOT_ALLOWED`
|
|
226
276
|
|
|
227
|
-
|
|
277
|
+
**---**
|
|
228
278
|
|
|
229
279
|
### `type`
|
|
230
280
|
|
|
@@ -235,19 +285,33 @@ Supported values:
|
|
|
235
285
|
```text
|
|
236
286
|
|
|
237
287
|
number
|
|
288
|
+
|
|
238
289
|
string
|
|
290
|
+
|
|
239
291
|
boolean
|
|
292
|
+
|
|
240
293
|
email
|
|
294
|
+
|
|
241
295
|
url
|
|
296
|
+
|
|
242
297
|
enum
|
|
298
|
+
|
|
243
299
|
uuid
|
|
300
|
+
|
|
244
301
|
uuidv1
|
|
302
|
+
|
|
245
303
|
uuidv3
|
|
304
|
+
|
|
246
305
|
uuidv4
|
|
306
|
+
|
|
247
307
|
uuidv5
|
|
308
|
+
|
|
248
309
|
objectId
|
|
310
|
+
|
|
249
311
|
array
|
|
312
|
+
|
|
250
313
|
object
|
|
314
|
+
|
|
251
315
|
```
|
|
252
316
|
|
|
253
317
|
Example:
|
|
@@ -257,9 +321,11 @@ const rules = {
|
|
|
257
321
|
age: {
|
|
258
322
|
type: "number",
|
|
259
323
|
},
|
|
324
|
+
|
|
260
325
|
email: {
|
|
261
326
|
type: "email",
|
|
262
327
|
},
|
|
328
|
+
|
|
263
329
|
active: {
|
|
264
330
|
type: "boolean",
|
|
265
331
|
},
|
|
@@ -280,6 +346,7 @@ Example:
|
|
|
280
346
|
const rules = {
|
|
281
347
|
status: {
|
|
282
348
|
type: "enum",
|
|
349
|
+
|
|
283
350
|
enumValues: ["active", "inactive", "blocked", 1, 0],
|
|
284
351
|
},
|
|
285
352
|
};
|
|
@@ -299,6 +366,7 @@ Example:
|
|
|
299
366
|
const rules = {
|
|
300
367
|
status: {
|
|
301
368
|
type: "enum",
|
|
369
|
+
|
|
302
370
|
enumValues: ["active", "inactive", "blocked"],
|
|
303
371
|
},
|
|
304
372
|
};
|
|
@@ -311,18 +379,28 @@ Possible error codes for types:
|
|
|
311
379
|
```text
|
|
312
380
|
|
|
313
381
|
INVALID_TYPE
|
|
382
|
+
|
|
314
383
|
INVALID_EMAIL
|
|
384
|
+
|
|
315
385
|
INVALID_URL
|
|
386
|
+
|
|
316
387
|
INVALID_ENUM
|
|
388
|
+
|
|
317
389
|
INVALID_UUID
|
|
390
|
+
|
|
318
391
|
INVALID_UUID_V1
|
|
392
|
+
|
|
319
393
|
INVALID_UUID_V3
|
|
394
|
+
|
|
320
395
|
INVALID_UUID_V4
|
|
396
|
+
|
|
321
397
|
INVALID_UUID_V5
|
|
398
|
+
|
|
322
399
|
INVALID_OBJECT_ID
|
|
400
|
+
|
|
323
401
|
```
|
|
324
402
|
|
|
325
|
-
|
|
403
|
+
**---**
|
|
326
404
|
|
|
327
405
|
### `regex`
|
|
328
406
|
|
|
@@ -336,6 +414,7 @@ Example:
|
|
|
336
414
|
const rules = {
|
|
337
415
|
employeeCode: {
|
|
338
416
|
type: "string",
|
|
417
|
+
|
|
339
418
|
regex: /^[A-Z]{3}[0-9]{3}$/,
|
|
340
419
|
},
|
|
341
420
|
};
|
|
@@ -343,7 +422,7 @@ const rules = {
|
|
|
343
422
|
|
|
344
423
|
Error code: `REGEX_MISMATCH`
|
|
345
424
|
|
|
346
|
-
|
|
425
|
+
**---**
|
|
347
426
|
|
|
348
427
|
### `minLength`
|
|
349
428
|
|
|
@@ -357,6 +436,7 @@ Example:
|
|
|
357
436
|
const rules = {
|
|
358
437
|
username: {
|
|
359
438
|
type: "string",
|
|
439
|
+
|
|
360
440
|
minLength: 5,
|
|
361
441
|
},
|
|
362
442
|
};
|
|
@@ -364,7 +444,7 @@ const rules = {
|
|
|
364
444
|
|
|
365
445
|
Error code: `MIN_LENGTH`
|
|
366
446
|
|
|
367
|
-
|
|
447
|
+
**---**
|
|
368
448
|
|
|
369
449
|
### `maxLength`
|
|
370
450
|
|
|
@@ -378,6 +458,7 @@ Example:
|
|
|
378
458
|
const rules = {
|
|
379
459
|
username: {
|
|
380
460
|
type: "string",
|
|
461
|
+
|
|
381
462
|
maxLength: 20,
|
|
382
463
|
},
|
|
383
464
|
};
|
|
@@ -385,7 +466,7 @@ const rules = {
|
|
|
385
466
|
|
|
386
467
|
Error code: `MAX_LENGTH`
|
|
387
468
|
|
|
388
|
-
|
|
469
|
+
**---**
|
|
389
470
|
|
|
390
471
|
### `preventDecimal`
|
|
391
472
|
|
|
@@ -399,6 +480,7 @@ Example:
|
|
|
399
480
|
const rules = {
|
|
400
481
|
quantity: {
|
|
401
482
|
type: "number",
|
|
483
|
+
|
|
402
484
|
preventDecimal: true,
|
|
403
485
|
},
|
|
404
486
|
};
|
|
@@ -406,7 +488,7 @@ const rules = {
|
|
|
406
488
|
|
|
407
489
|
Error code: `DECIMAL_NOT_ALLOWED`
|
|
408
490
|
|
|
409
|
-
|
|
491
|
+
**---**
|
|
410
492
|
|
|
411
493
|
### `min`
|
|
412
494
|
|
|
@@ -420,6 +502,7 @@ Example:
|
|
|
420
502
|
const rules = {
|
|
421
503
|
age: {
|
|
422
504
|
type: "number",
|
|
505
|
+
|
|
423
506
|
min: 18,
|
|
424
507
|
},
|
|
425
508
|
};
|
|
@@ -427,7 +510,7 @@ const rules = {
|
|
|
427
510
|
|
|
428
511
|
Error code: `MIN_VALUE`
|
|
429
512
|
|
|
430
|
-
|
|
513
|
+
**---**
|
|
431
514
|
|
|
432
515
|
### `max`
|
|
433
516
|
|
|
@@ -441,6 +524,7 @@ Example:
|
|
|
441
524
|
const rules = {
|
|
442
525
|
quantity: {
|
|
443
526
|
type: "number",
|
|
527
|
+
|
|
444
528
|
max: 100,
|
|
445
529
|
},
|
|
446
530
|
};
|
|
@@ -448,7 +532,7 @@ const rules = {
|
|
|
448
532
|
|
|
449
533
|
Error code: `MAX_VALUE`
|
|
450
534
|
|
|
451
|
-
|
|
535
|
+
**---**
|
|
452
536
|
|
|
453
537
|
### `range`
|
|
454
538
|
|
|
@@ -462,6 +546,7 @@ Example:
|
|
|
462
546
|
const rules = {
|
|
463
547
|
marks: {
|
|
464
548
|
type: "number",
|
|
549
|
+
|
|
465
550
|
range: "0-100",
|
|
466
551
|
},
|
|
467
552
|
};
|
|
@@ -469,7 +554,7 @@ const rules = {
|
|
|
469
554
|
|
|
470
555
|
Error code: `OUT_OF_RANGE`
|
|
471
556
|
|
|
472
|
-
|
|
557
|
+
**---**
|
|
473
558
|
|
|
474
559
|
### `elementConstraints`
|
|
475
560
|
|
|
@@ -481,8 +566,10 @@ Example:
|
|
|
481
566
|
const rules = {
|
|
482
567
|
marks: {
|
|
483
568
|
type: "array",
|
|
569
|
+
|
|
484
570
|
elementConstraints: {
|
|
485
571
|
type: "number",
|
|
572
|
+
|
|
486
573
|
range: "0-100",
|
|
487
574
|
},
|
|
488
575
|
},
|
|
@@ -495,14 +582,20 @@ Example error:
|
|
|
495
582
|
|
|
496
583
|
{
|
|
497
584
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
585
|
+
path: "marks[2]",
|
|
586
|
+
|
|
587
|
+
code: "OUT_OF_RANGE",
|
|
588
|
+
|
|
589
|
+
message:
|
|
590
|
+
|
|
591
|
+
"Attribute marks[2] should have a value between 0 and 100"
|
|
592
|
+
|
|
502
593
|
}
|
|
594
|
+
|
|
503
595
|
```
|
|
504
596
|
|
|
505
597
|
When `elementConstraintsError` is explicitly provided, the error code
|
|
598
|
+
|
|
506
599
|
is: `INVALID_ARRAY_ELEMENT`
|
|
507
600
|
|
|
508
601
|
Example:
|
|
@@ -511,15 +604,17 @@ Example:
|
|
|
511
604
|
const rules = {
|
|
512
605
|
marks: {
|
|
513
606
|
type: "array",
|
|
607
|
+
|
|
514
608
|
elementConstraints: {
|
|
515
609
|
type: "number",
|
|
516
610
|
},
|
|
611
|
+
|
|
517
612
|
elementConstraintsError: "Every marks element must be a number",
|
|
518
613
|
},
|
|
519
614
|
};
|
|
520
615
|
```
|
|
521
616
|
|
|
522
|
-
|
|
617
|
+
**---**
|
|
523
618
|
|
|
524
619
|
### `objectAttr`
|
|
525
620
|
|
|
@@ -531,17 +626,22 @@ Example:
|
|
|
531
626
|
const rules = {
|
|
532
627
|
address: {
|
|
533
628
|
type: "object",
|
|
629
|
+
|
|
534
630
|
objectAttr: {
|
|
535
631
|
city: {
|
|
536
632
|
mandatory: true,
|
|
633
|
+
|
|
537
634
|
type: "string",
|
|
538
635
|
},
|
|
636
|
+
|
|
539
637
|
location: {
|
|
540
638
|
type: "object",
|
|
639
|
+
|
|
541
640
|
objectAttr: {
|
|
542
641
|
latitude: {
|
|
543
642
|
type: "number",
|
|
544
643
|
},
|
|
644
|
+
|
|
545
645
|
longitude: {
|
|
546
646
|
type: "number",
|
|
547
647
|
},
|
|
@@ -557,14 +657,20 @@ Nested errors include the complete field path:
|
|
|
557
657
|
```js
|
|
558
658
|
|
|
559
659
|
{
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
660
|
+
|
|
661
|
+
path: "address.location.latitude",
|
|
662
|
+
|
|
663
|
+
code: "INVALID_TYPE",
|
|
664
|
+
|
|
665
|
+
message:
|
|
666
|
+
|
|
667
|
+
"Invalid type for attribute address.location.latitude, required number value"
|
|
668
|
+
|
|
564
669
|
}
|
|
670
|
+
|
|
565
671
|
```
|
|
566
672
|
|
|
567
|
-
|
|
673
|
+
**---**
|
|
568
674
|
|
|
569
675
|
### `dependency`
|
|
570
676
|
|
|
@@ -576,11 +682,14 @@ Example:
|
|
|
576
682
|
const rules = {
|
|
577
683
|
minSalary: {
|
|
578
684
|
type: "number",
|
|
685
|
+
|
|
579
686
|
dependency: {
|
|
580
687
|
maxSalary: {
|
|
581
688
|
setDependencyRule: (minSalary, maxSalary) => ({
|
|
582
689
|
type: "number",
|
|
690
|
+
|
|
583
691
|
min: minSalary + 1,
|
|
692
|
+
|
|
584
693
|
minError: "maxSalary must be more than minSalary",
|
|
585
694
|
}),
|
|
586
695
|
},
|
|
@@ -595,61 +704,182 @@ Example error:
|
|
|
595
704
|
|
|
596
705
|
{
|
|
597
706
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
707
|
+
path: "maxSalary",
|
|
708
|
+
|
|
709
|
+
code: "MIN_VALUE",
|
|
710
|
+
|
|
711
|
+
message:
|
|
712
|
+
|
|
713
|
+
"maxSalary must be more than minSalary"
|
|
714
|
+
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
**---**
|
|
720
|
+
|
|
721
|
+
### `customValidator`
|
|
722
|
+
|
|
723
|
+
Allows you to define custom synchronous validation logic for a field when the built-in validation rules are not enough.
|
|
724
|
+
|
|
725
|
+
The validator receives the field value and the complete payload:
|
|
726
|
+
|
|
727
|
+
```js
|
|
728
|
+
customValidator: (value, payload) => {
|
|
729
|
+
return true;
|
|
730
|
+
};
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
The validator must return `true` to pass validation. Any other return value causes validation to fail.
|
|
734
|
+
|
|
735
|
+
Example:
|
|
736
|
+
|
|
737
|
+
```js
|
|
738
|
+
const rules = {
|
|
739
|
+
username: {
|
|
740
|
+
mandatory: true,
|
|
741
|
+
type: "string",
|
|
742
|
+
customValidator: (value) => {
|
|
743
|
+
return !value.toLowerCase().includes("admin");
|
|
744
|
+
},
|
|
745
|
+
customValidatorCode: "RESERVED_USERNAME",
|
|
746
|
+
customValidatorError: "Username cannot contain admin",
|
|
747
|
+
},
|
|
748
|
+
};
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
For this payload:
|
|
752
|
+
|
|
753
|
+
```js
|
|
754
|
+
const payload = {
|
|
755
|
+
username: "admin_kiran",
|
|
756
|
+
};
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
The validation error is:
|
|
760
|
+
|
|
761
|
+
```js
|
|
762
|
+
{
|
|
763
|
+
path: "username",
|
|
764
|
+
code: "RESERVED_USERNAME",
|
|
765
|
+
message: "Username cannot contain admin"
|
|
766
|
+
}
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
If `customValidatorCode` and `customValidatorError` are not provided, the default error is:
|
|
770
|
+
|
|
771
|
+
```js
|
|
772
|
+
{
|
|
773
|
+
path: "username",
|
|
774
|
+
code: "CUSTOM_VALIDATION_FAILED",
|
|
775
|
+
message: "Custom validation failed for attribute username"
|
|
602
776
|
}
|
|
603
777
|
```
|
|
604
778
|
|
|
779
|
+
The complete payload can be used as the second argument when required:
|
|
780
|
+
|
|
781
|
+
```js
|
|
782
|
+
const rules = {
|
|
783
|
+
limit: {
|
|
784
|
+
type: "number",
|
|
785
|
+
},
|
|
786
|
+
amount: {
|
|
787
|
+
type: "number",
|
|
788
|
+
customValidator: (value, payload) => {
|
|
789
|
+
return value <= payload.limit;
|
|
790
|
+
},
|
|
791
|
+
customValidatorCode: "LIMIT_EXCEEDED",
|
|
792
|
+
customValidatorError: "Amount cannot exceed limit",
|
|
793
|
+
},
|
|
794
|
+
};
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
`customValidator` also works with nested objects and array `elementConstraints`. The generated structured error automatically contains the corresponding nested or array path.
|
|
798
|
+
|
|
799
|
+
**Important:** `customValidator` is synchronous. An `async` validator or a validator that returns a Promise is not supported and throws an error. Asynchronous validation is not part of this feature.
|
|
800
|
+
|
|
801
|
+
Error code when no custom code is provided: `CUSTOM_VALIDATION_FAILED`
|
|
802
|
+
|
|
605
803
|
## Error Codes
|
|
606
804
|
|
|
607
805
|
`perfectPayload()` currently exposes the following machine-readable
|
|
806
|
+
|
|
608
807
|
validation error codes:
|
|
609
808
|
|
|
610
809
|
```text
|
|
611
810
|
|
|
612
811
|
REQUIRED
|
|
812
|
+
|
|
613
813
|
NULL_NOT_ALLOWED
|
|
814
|
+
|
|
614
815
|
EMPTY_OBJECT_NOT_ALLOWED
|
|
816
|
+
|
|
615
817
|
EMPTY_ARRAY_NOT_ALLOWED
|
|
818
|
+
|
|
616
819
|
INVALID_ARRAY_ELEMENT
|
|
820
|
+
|
|
617
821
|
REGEX_MISMATCH
|
|
822
|
+
|
|
618
823
|
INVALID_TYPE
|
|
824
|
+
|
|
619
825
|
INVALID_EMAIL
|
|
826
|
+
|
|
620
827
|
INVALID_URL
|
|
828
|
+
|
|
621
829
|
INVALID_ENUM
|
|
830
|
+
|
|
622
831
|
INVALID_UUID
|
|
832
|
+
|
|
623
833
|
INVALID_UUID_V1
|
|
834
|
+
|
|
624
835
|
INVALID_UUID_V3
|
|
836
|
+
|
|
625
837
|
INVALID_UUID_V4
|
|
838
|
+
|
|
626
839
|
INVALID_UUID_V5
|
|
840
|
+
|
|
627
841
|
INVALID_OBJECT_ID
|
|
842
|
+
|
|
628
843
|
MIN_LENGTH
|
|
844
|
+
|
|
629
845
|
MAX_LENGTH
|
|
846
|
+
|
|
630
847
|
DECIMAL_NOT_ALLOWED
|
|
848
|
+
|
|
631
849
|
MIN_VALUE
|
|
850
|
+
|
|
632
851
|
MAX_VALUE
|
|
852
|
+
|
|
633
853
|
OUT_OF_RANGE
|
|
854
|
+
|
|
634
855
|
```
|
|
635
856
|
|
|
636
857
|
These codes are designed for programmatic handling while `message`
|
|
858
|
+
|
|
637
859
|
remains suitable for human-readable API responses.
|
|
638
860
|
|
|
639
861
|
For example:
|
|
640
862
|
|
|
641
863
|
```js
|
|
864
|
+
|
|
642
865
|
const result = perfectPayload(payload, validationRules);
|
|
643
866
|
|
|
644
867
|
if (!result.valid) {
|
|
868
|
+
|
|
645
869
|
const emailError = result.errors.find(
|
|
870
|
+
|
|
646
871
|
(error) => error.code === "INVALID_EMAIL",
|
|
872
|
+
|
|
647
873
|
);
|
|
648
874
|
|
|
649
875
|
if (emailError) {
|
|
650
|
-
|
|
876
|
+
|
|
877
|
+
*// Handle invalid email*
|
|
878
|
+
|
|
651
879
|
}
|
|
880
|
+
|
|
652
881
|
}
|
|
882
|
+
|
|
653
883
|
```
|
|
654
884
|
|
|
655
885
|
## Custom Error Messages
|
|
@@ -657,15 +887,21 @@ if (!result.valid) {
|
|
|
657
887
|
Every validation rule can use its corresponding custom error message.
|
|
658
888
|
|
|
659
889
|
Custom messages replace the default human-readable `message` while
|
|
890
|
+
|
|
660
891
|
keeping the same structured error format:
|
|
661
892
|
|
|
662
893
|
```js
|
|
663
894
|
|
|
664
895
|
{
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
896
|
+
|
|
897
|
+
path: "email",
|
|
898
|
+
|
|
899
|
+
code: "INVALID_EMAIL",
|
|
900
|
+
|
|
901
|
+
message: "Email address is invalid"
|
|
902
|
+
|
|
668
903
|
}
|
|
904
|
+
|
|
669
905
|
```
|
|
670
906
|
|
|
671
907
|
Example:
|
|
@@ -674,8 +910,11 @@ Example:
|
|
|
674
910
|
const rules = {
|
|
675
911
|
email: {
|
|
676
912
|
mandatory: true,
|
|
913
|
+
|
|
677
914
|
type: "email",
|
|
915
|
+
|
|
678
916
|
mandatoryError: "Email is required",
|
|
917
|
+
|
|
679
918
|
typeError: "Email address is invalid",
|
|
680
919
|
},
|
|
681
920
|
};
|
|
@@ -686,10 +925,15 @@ If `email` is missing:
|
|
|
686
925
|
```js
|
|
687
926
|
|
|
688
927
|
{
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
928
|
+
|
|
929
|
+
path: "email",
|
|
930
|
+
|
|
931
|
+
code: "REQUIRED",
|
|
932
|
+
|
|
933
|
+
message: "Email is required"
|
|
934
|
+
|
|
692
935
|
}
|
|
936
|
+
|
|
693
937
|
```
|
|
694
938
|
|
|
695
939
|
If `email` is present but invalid:
|
|
@@ -697,70 +941,88 @@ If `email` is present but invalid:
|
|
|
697
941
|
```js
|
|
698
942
|
|
|
699
943
|
{
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
944
|
+
|
|
945
|
+
path: "email",
|
|
946
|
+
|
|
947
|
+
code: "INVALID_EMAIL",
|
|
948
|
+
|
|
949
|
+
message: "Email address is invalid"
|
|
950
|
+
|
|
703
951
|
}
|
|
952
|
+
|
|
704
953
|
```
|
|
705
954
|
|
|
706
955
|
### Supported Custom Error Properties
|
|
707
956
|
|
|
708
|
-
\| Validation Rule
|
|
957
|
+
\| Validation Rule \| Custom Error Property \|
|
|
709
958
|
|
|
710
959
|
\| -------------------- \| ------------------------- \|
|
|
711
960
|
|
|
712
|
-
\| `mandatory`
|
|
961
|
+
\| `mandatory` \| `mandatoryError` \|
|
|
713
962
|
|
|
714
|
-
\| `allowNull`
|
|
963
|
+
\| `allowNull` \| `allowNullError` \|
|
|
715
964
|
|
|
716
|
-
\| `allowEmptyObject`
|
|
965
|
+
\| `allowEmptyObject` \| `emptyObjectError` \|
|
|
717
966
|
|
|
718
|
-
\| `allowEmptyArray`
|
|
967
|
+
\| `allowEmptyArray` \| `emptyArrayError` \|
|
|
719
968
|
|
|
720
969
|
\| `elementConstraints` \| `elementConstraintsError` \|
|
|
721
970
|
|
|
722
|
-
\| `regex`
|
|
971
|
+
\| `regex` \| `regexError` \|
|
|
723
972
|
|
|
724
|
-
\| `type`
|
|
973
|
+
\| `type` \| `typeError` \|
|
|
725
974
|
|
|
726
|
-
\| `minLength`
|
|
975
|
+
\| `minLength` \| `minLengthError` \|
|
|
727
976
|
|
|
728
|
-
\| `maxLength`
|
|
977
|
+
\| `maxLength` \| `maxLengthError` \|
|
|
729
978
|
|
|
730
|
-
\| `preventDecimal`
|
|
979
|
+
\| `preventDecimal` \| `preventDecimalError` \|
|
|
731
980
|
|
|
732
|
-
\| `min`
|
|
981
|
+
\| `min` \| `minError` \|
|
|
733
982
|
|
|
734
|
-
\| `max`
|
|
983
|
+
\| `max` \| `maxError` \|
|
|
735
984
|
|
|
736
|
-
\| `range`
|
|
985
|
+
\| `range` \| `rangeError` \|
|
|
737
986
|
|
|
738
987
|
### Example with Multiple Custom Errors
|
|
739
988
|
|
|
740
989
|
```js
|
|
741
990
|
const payload = {
|
|
742
991
|
username: "ab",
|
|
992
|
+
|
|
743
993
|
age: 15,
|
|
994
|
+
|
|
744
995
|
score: 120,
|
|
745
996
|
};
|
|
746
997
|
|
|
747
998
|
const rules = {
|
|
748
999
|
username: {
|
|
749
1000
|
mandatory: true,
|
|
1001
|
+
|
|
750
1002
|
type: "string",
|
|
1003
|
+
|
|
751
1004
|
minLength: 3,
|
|
1005
|
+
|
|
752
1006
|
mandatoryError: "Username is required",
|
|
1007
|
+
|
|
753
1008
|
typeError: "Username must be a string",
|
|
1009
|
+
|
|
754
1010
|
minLengthError: "Username must contain at least 3 characters",
|
|
755
1011
|
},
|
|
1012
|
+
|
|
756
1013
|
age: {
|
|
757
1014
|
type: "number",
|
|
1015
|
+
|
|
758
1016
|
min: 18,
|
|
1017
|
+
|
|
759
1018
|
minError: "Age must be at least 18",
|
|
760
1019
|
},
|
|
1020
|
+
|
|
761
1021
|
score: {
|
|
762
1022
|
type: "number",
|
|
1023
|
+
|
|
763
1024
|
range: "0-100",
|
|
1025
|
+
|
|
764
1026
|
rangeError: "Score must be between 0 and 100",
|
|
765
1027
|
},
|
|
766
1028
|
};
|
|
@@ -773,72 +1035,109 @@ Example result:
|
|
|
773
1035
|
```js
|
|
774
1036
|
|
|
775
1037
|
{
|
|
776
|
-
statusCode: 400,
|
|
777
|
-
valid: false,
|
|
778
|
-
message:
|
|
779
|
-
"One or more attribute values are invalid",
|
|
780
|
-
errors: [
|
|
781
|
-
{
|
|
782
|
-
path: "username",
|
|
783
|
-
code: "MIN_LENGTH",
|
|
784
|
-
message:
|
|
785
|
-
"Username must contain at least 3 characters"
|
|
786
|
-
},
|
|
787
|
-
{
|
|
788
|
-
path: "age",
|
|
789
|
-
code: "MIN_VALUE",
|
|
790
|
-
message:
|
|
791
|
-
"Age must be at least 18"
|
|
792
|
-
},
|
|
793
|
-
{
|
|
794
|
-
path: "score",
|
|
795
|
-
code: "OUT_OF_RANGE",
|
|
796
|
-
message:
|
|
797
|
-
"Score must be between 0 and 100"
|
|
798
|
-
}
|
|
799
|
-
]
|
|
800
|
-
}
|
|
801
|
-
```
|
|
802
1038
|
|
|
803
|
-
|
|
1039
|
+
statusCode: 400,
|
|
804
1040
|
|
|
805
|
-
|
|
1041
|
+
valid: false,
|
|
806
1042
|
|
|
807
|
-
|
|
1043
|
+
message:
|
|
808
1044
|
|
|
809
|
-
|
|
1045
|
+
"One or more attribute values are invalid",
|
|
810
1046
|
|
|
811
|
-
|
|
812
|
-
const rules = {
|
|
813
|
-
age: {
|
|
814
|
-
type: "number",
|
|
815
|
-
min: 18,
|
|
816
|
-
minError: "You must be 18 or older",
|
|
817
|
-
},
|
|
818
|
-
};
|
|
819
|
-
```
|
|
1047
|
+
errors: [
|
|
820
1048
|
|
|
821
|
-
|
|
1049
|
+
{
|
|
822
1050
|
|
|
823
|
-
|
|
1051
|
+
path: "username",
|
|
824
1052
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1053
|
+
code: "MIN_LENGTH",
|
|
1054
|
+
|
|
1055
|
+
message:
|
|
1056
|
+
|
|
1057
|
+
"Username must contain at least 3 characters"
|
|
1058
|
+
|
|
1059
|
+
},
|
|
1060
|
+
|
|
1061
|
+
{
|
|
1062
|
+
|
|
1063
|
+
path: "age",
|
|
1064
|
+
|
|
1065
|
+
code: "MIN_VALUE",
|
|
1066
|
+
|
|
1067
|
+
message:
|
|
1068
|
+
|
|
1069
|
+
"Age must be at least 18"
|
|
1070
|
+
|
|
1071
|
+
},
|
|
1072
|
+
|
|
1073
|
+
{
|
|
1074
|
+
|
|
1075
|
+
path: "score",
|
|
1076
|
+
|
|
1077
|
+
code: "OUT_OF_RANGE",
|
|
1078
|
+
|
|
1079
|
+
message:
|
|
1080
|
+
|
|
1081
|
+
"Score must be between 0 and 100"
|
|
1082
|
+
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
]
|
|
1086
|
+
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
### Custom Messages and Error Codes
|
|
1092
|
+
|
|
1093
|
+
Custom messages only replace the `message`.
|
|
1094
|
+
|
|
1095
|
+
They do not change the validation error `code`.
|
|
1096
|
+
|
|
1097
|
+
For example:
|
|
1098
|
+
|
|
1099
|
+
```js
|
|
1100
|
+
const rules = {
|
|
1101
|
+
age: {
|
|
1102
|
+
type: "number",
|
|
1103
|
+
|
|
1104
|
+
min: 18,
|
|
1105
|
+
|
|
1106
|
+
minError: "You must be 18 or older",
|
|
1107
|
+
},
|
|
1108
|
+
};
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
Still returns:
|
|
1112
|
+
|
|
1113
|
+
```js
|
|
1114
|
+
|
|
1115
|
+
{
|
|
1116
|
+
|
|
1117
|
+
path: "age",
|
|
1118
|
+
|
|
1119
|
+
code: "MIN_VALUE",
|
|
1120
|
+
|
|
1121
|
+
message: "You must be 18 or older"
|
|
1122
|
+
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
```
|
|
831
1126
|
|
|
832
1127
|
This makes it possible to:
|
|
833
1128
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1129
|
+
\- show custom messages to API consumers
|
|
1130
|
+
|
|
1131
|
+
\- use stable error codes in application logic
|
|
1132
|
+
|
|
1133
|
+
\- change user-facing wording without changing programmatic error
|
|
1134
|
+
|
|
1135
|
+
handling
|
|
838
1136
|
|
|
839
1137
|
## Custom Response Objects
|
|
840
1138
|
|
|
841
1139
|
`perfectPayload()` allows you to customize both the valid and invalid
|
|
1140
|
+
|
|
842
1141
|
response objects.
|
|
843
1142
|
|
|
844
1143
|
The third argument is the custom valid response.
|
|
@@ -852,7 +1151,9 @@ Example:
|
|
|
852
1151
|
```js
|
|
853
1152
|
const customValidResponse = {
|
|
854
1153
|
statusCode: 201,
|
|
1154
|
+
|
|
855
1155
|
valid: true,
|
|
1156
|
+
|
|
856
1157
|
message: "Payload validated successfully",
|
|
857
1158
|
};
|
|
858
1159
|
|
|
@@ -864,15 +1165,25 @@ When validation succeeds, `validatedPayload` is automatically added:
|
|
|
864
1165
|
```js
|
|
865
1166
|
|
|
866
1167
|
{
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1168
|
+
|
|
1169
|
+
statusCode: 201,
|
|
1170
|
+
|
|
1171
|
+
valid: true,
|
|
1172
|
+
|
|
1173
|
+
message: "Payload validated successfully",
|
|
1174
|
+
|
|
1175
|
+
validatedPayload: {
|
|
1176
|
+
|
|
1177
|
+
name: "Kiran",
|
|
1178
|
+
|
|
1179
|
+
email: "kiran@example.com",
|
|
1180
|
+
|
|
1181
|
+
age: 29
|
|
1182
|
+
|
|
1183
|
+
}
|
|
1184
|
+
|
|
875
1185
|
}
|
|
1186
|
+
|
|
876
1187
|
```
|
|
877
1188
|
|
|
878
1189
|
### Custom Invalid Response
|
|
@@ -882,14 +1193,19 @@ Example:
|
|
|
882
1193
|
```js
|
|
883
1194
|
const customInvalidResponse = {
|
|
884
1195
|
statusCode: 422,
|
|
1196
|
+
|
|
885
1197
|
valid: false,
|
|
1198
|
+
|
|
886
1199
|
message: "Payload validation failed",
|
|
887
1200
|
};
|
|
888
1201
|
|
|
889
1202
|
const result = perfectPayload(
|
|
890
1203
|
payload,
|
|
1204
|
+
|
|
891
1205
|
validationRules,
|
|
1206
|
+
|
|
892
1207
|
undefined,
|
|
1208
|
+
|
|
893
1209
|
customInvalidResponse,
|
|
894
1210
|
);
|
|
895
1211
|
```
|
|
@@ -900,18 +1216,30 @@ When validation fails, `errors` is automatically added:
|
|
|
900
1216
|
|
|
901
1217
|
{
|
|
902
1218
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1219
|
+
statusCode: 422,
|
|
1220
|
+
|
|
1221
|
+
valid: false,
|
|
1222
|
+
|
|
1223
|
+
message: "Payload validation failed",
|
|
1224
|
+
|
|
1225
|
+
errors: [
|
|
1226
|
+
|
|
1227
|
+
{
|
|
1228
|
+
|
|
1229
|
+
path: "email",
|
|
1230
|
+
|
|
1231
|
+
code: "INVALID_EMAIL",
|
|
1232
|
+
|
|
1233
|
+
message:
|
|
1234
|
+
|
|
1235
|
+
"Invalid email format for attribute email"
|
|
1236
|
+
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
]
|
|
1240
|
+
|
|
914
1241
|
}
|
|
1242
|
+
|
|
915
1243
|
```
|
|
916
1244
|
|
|
917
1245
|
### Custom Valid and Invalid Responses Together
|
|
@@ -919,30 +1247,39 @@ When validation fails, `errors` is automatically added:
|
|
|
919
1247
|
```js
|
|
920
1248
|
const customValidResponse = {
|
|
921
1249
|
statusCode: 201,
|
|
1250
|
+
|
|
922
1251
|
valid: true,
|
|
1252
|
+
|
|
923
1253
|
message: "CUSTOM_VALID_RESPONSE",
|
|
924
1254
|
};
|
|
925
1255
|
|
|
926
1256
|
const customInvalidResponse = {
|
|
927
1257
|
statusCode: 422,
|
|
1258
|
+
|
|
928
1259
|
valid: false,
|
|
1260
|
+
|
|
929
1261
|
message: "CUSTOM_INVALID_RESPONSE",
|
|
930
1262
|
};
|
|
931
1263
|
|
|
932
1264
|
const result = perfectPayload(
|
|
933
1265
|
payload,
|
|
1266
|
+
|
|
934
1267
|
validationRules,
|
|
1268
|
+
|
|
935
1269
|
customValidResponse,
|
|
1270
|
+
|
|
936
1271
|
customInvalidResponse,
|
|
937
1272
|
);
|
|
938
1273
|
```
|
|
939
1274
|
|
|
940
1275
|
The response object you provide is preserved, while `perfectPayload()`
|
|
1276
|
+
|
|
941
1277
|
automatically adds either:
|
|
942
1278
|
|
|
943
1279
|
```text
|
|
944
1280
|
|
|
945
1281
|
validatedPayload
|
|
1282
|
+
|
|
946
1283
|
```
|
|
947
1284
|
|
|
948
1285
|
for successful validation, or:
|
|
@@ -950,6 +1287,7 @@ for successful validation, or:
|
|
|
950
1287
|
```text
|
|
951
1288
|
|
|
952
1289
|
errors
|
|
1290
|
+
|
|
953
1291
|
```
|
|
954
1292
|
|
|
955
1293
|
for failed validation.
|
|
@@ -957,17 +1295,25 @@ for failed validation.
|
|
|
957
1295
|
## Default Responses
|
|
958
1296
|
|
|
959
1297
|
If no custom response objects are provided, the default valid response
|
|
1298
|
+
|
|
960
1299
|
is:
|
|
961
1300
|
|
|
962
1301
|
```js
|
|
963
1302
|
|
|
964
1303
|
{
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1304
|
+
|
|
1305
|
+
statusCode: 200,
|
|
1306
|
+
|
|
1307
|
+
valid: true,
|
|
1308
|
+
|
|
1309
|
+
validatedPayload: {
|
|
1310
|
+
|
|
1311
|
+
*// validated fields*
|
|
1312
|
+
|
|
1313
|
+
}
|
|
1314
|
+
|
|
970
1315
|
}
|
|
1316
|
+
|
|
971
1317
|
```
|
|
972
1318
|
|
|
973
1319
|
The default invalid response is:
|
|
@@ -975,25 +1321,39 @@ The default invalid response is:
|
|
|
975
1321
|
```js
|
|
976
1322
|
|
|
977
1323
|
{
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1324
|
+
|
|
1325
|
+
statusCode: 400,
|
|
1326
|
+
|
|
1327
|
+
valid: false,
|
|
1328
|
+
|
|
1329
|
+
message: "One or more attribute values are invalid",
|
|
1330
|
+
|
|
1331
|
+
errors: [
|
|
1332
|
+
|
|
1333
|
+
{
|
|
1334
|
+
|
|
1335
|
+
path: "field",
|
|
1336
|
+
|
|
1337
|
+
code: "ERROR_CODE",
|
|
1338
|
+
|
|
1339
|
+
message: "Validation error message"
|
|
1340
|
+
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
]
|
|
1344
|
+
|
|
988
1345
|
}
|
|
1346
|
+
|
|
989
1347
|
```
|
|
990
1348
|
|
|
991
1349
|
## Nested Objects and Array Field Paths
|
|
992
1350
|
|
|
993
1351
|
`perfectPayload()` returns the exact location of a validation failure
|
|
1352
|
+
|
|
994
1353
|
through the `path` property.
|
|
995
1354
|
|
|
996
1355
|
This makes validation errors easier to map to API fields, forms, logs,
|
|
1356
|
+
|
|
997
1357
|
and frontend components.
|
|
998
1358
|
|
|
999
1359
|
### Top-Level Field
|
|
@@ -1011,10 +1371,15 @@ An error can be returned as:
|
|
|
1011
1371
|
```js
|
|
1012
1372
|
|
|
1013
1373
|
{
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1374
|
+
|
|
1375
|
+
path: "email",
|
|
1376
|
+
|
|
1377
|
+
code: "INVALID_EMAIL",
|
|
1378
|
+
|
|
1379
|
+
message: "Invalid email format for attribute email"
|
|
1380
|
+
|
|
1017
1381
|
}
|
|
1382
|
+
|
|
1018
1383
|
```
|
|
1019
1384
|
|
|
1020
1385
|
### Nested Object
|
|
@@ -1025,8 +1390,10 @@ Use `objectAttr` to validate properties inside an object.
|
|
|
1025
1390
|
const payload = {
|
|
1026
1391
|
address: {
|
|
1027
1392
|
city: "Bengaluru",
|
|
1393
|
+
|
|
1028
1394
|
location: {
|
|
1029
1395
|
latitude: "12.9716",
|
|
1396
|
+
|
|
1030
1397
|
longitude: 77.5946,
|
|
1031
1398
|
},
|
|
1032
1399
|
},
|
|
@@ -1035,16 +1402,20 @@ const payload = {
|
|
|
1035
1402
|
const rules = {
|
|
1036
1403
|
address: {
|
|
1037
1404
|
type: "object",
|
|
1405
|
+
|
|
1038
1406
|
objectAttr: {
|
|
1039
1407
|
city: {
|
|
1040
1408
|
type: "string",
|
|
1041
1409
|
},
|
|
1410
|
+
|
|
1042
1411
|
location: {
|
|
1043
1412
|
type: "object",
|
|
1413
|
+
|
|
1044
1414
|
objectAttr: {
|
|
1045
1415
|
latitude: {
|
|
1046
1416
|
type: "number",
|
|
1047
1417
|
},
|
|
1418
|
+
|
|
1048
1419
|
longitude: {
|
|
1049
1420
|
type: "number",
|
|
1050
1421
|
},
|
|
@@ -1058,16 +1429,23 @@ const result = perfectPayload(payload, rules);
|
|
|
1058
1429
|
```
|
|
1059
1430
|
|
|
1060
1431
|
Because `latitude` is a string instead of a number, the error contains
|
|
1432
|
+
|
|
1061
1433
|
its complete nested path:
|
|
1062
1434
|
|
|
1063
1435
|
```js
|
|
1064
1436
|
|
|
1065
1437
|
{
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1438
|
+
|
|
1439
|
+
path: "address.location.latitude",
|
|
1440
|
+
|
|
1441
|
+
code: "INVALID_TYPE",
|
|
1442
|
+
|
|
1443
|
+
message:
|
|
1444
|
+
|
|
1445
|
+
"Invalid type for attribute address.location.latitude, required number value"
|
|
1446
|
+
|
|
1070
1447
|
}
|
|
1448
|
+
|
|
1071
1449
|
```
|
|
1072
1450
|
|
|
1073
1451
|
Nested paths use dot notation:
|
|
@@ -1075,13 +1453,17 @@ Nested paths use dot notation:
|
|
|
1075
1453
|
```text
|
|
1076
1454
|
|
|
1077
1455
|
address.city
|
|
1456
|
+
|
|
1078
1457
|
address.location.latitude
|
|
1458
|
+
|
|
1079
1459
|
address.location.longitude
|
|
1460
|
+
|
|
1080
1461
|
```
|
|
1081
1462
|
|
|
1082
1463
|
### Array Elements
|
|
1083
1464
|
|
|
1084
1465
|
When `elementConstraints` validation fails, the array index is included
|
|
1466
|
+
|
|
1085
1467
|
in the error path.
|
|
1086
1468
|
|
|
1087
1469
|
```js
|
|
@@ -1092,8 +1474,10 @@ const payload = {
|
|
|
1092
1474
|
const rules = {
|
|
1093
1475
|
marks: {
|
|
1094
1476
|
type: "array",
|
|
1477
|
+
|
|
1095
1478
|
elementConstraints: {
|
|
1096
1479
|
type: "number",
|
|
1480
|
+
|
|
1097
1481
|
range: "0-100",
|
|
1098
1482
|
},
|
|
1099
1483
|
},
|
|
@@ -1107,11 +1491,17 @@ The invalid third element is reported as:
|
|
|
1107
1491
|
```js
|
|
1108
1492
|
|
|
1109
1493
|
{
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1494
|
+
|
|
1495
|
+
path: "marks[2]",
|
|
1496
|
+
|
|
1497
|
+
code: "OUT_OF_RANGE",
|
|
1498
|
+
|
|
1499
|
+
message:
|
|
1500
|
+
|
|
1501
|
+
"Attribute marks[2] should have a value between 0 and 100"
|
|
1502
|
+
|
|
1114
1503
|
}
|
|
1504
|
+
|
|
1115
1505
|
```
|
|
1116
1506
|
|
|
1117
1507
|
Array paths use zero-based indexes:
|
|
@@ -1119,8 +1509,11 @@ Array paths use zero-based indexes:
|
|
|
1119
1509
|
```text
|
|
1120
1510
|
|
|
1121
1511
|
marks[0]
|
|
1512
|
+
|
|
1122
1513
|
marks[1]
|
|
1514
|
+
|
|
1123
1515
|
marks[2]
|
|
1516
|
+
|
|
1124
1517
|
```
|
|
1125
1518
|
|
|
1126
1519
|
### Nested Fields Inside Arrays
|
|
@@ -1132,16 +1525,21 @@ For example:
|
|
|
1132
1525
|
```text
|
|
1133
1526
|
|
|
1134
1527
|
products[0].quantity
|
|
1528
|
+
|
|
1135
1529
|
products[1].quantity
|
|
1530
|
+
|
|
1136
1531
|
products[2].price
|
|
1532
|
+
|
|
1137
1533
|
```
|
|
1138
1534
|
|
|
1139
1535
|
This provides enough information for consumers to identify the exact
|
|
1536
|
+
|
|
1140
1537
|
field that caused the validation error.
|
|
1141
1538
|
|
|
1142
1539
|
### Why Structured Paths Are Useful
|
|
1143
1540
|
|
|
1144
1541
|
Instead of parsing an error message to determine which field failed,
|
|
1542
|
+
|
|
1145
1543
|
applications can directly use:
|
|
1146
1544
|
|
|
1147
1545
|
```js
|
|
@@ -1176,11 +1574,14 @@ Result:
|
|
|
1176
1574
|
|
|
1177
1575
|
{
|
|
1178
1576
|
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1577
|
+
"email": "Invalid email format for attribute email",
|
|
1578
|
+
|
|
1579
|
+
"address.location.latitude": "Invalid type for attribute address.location.latitude, required number value",
|
|
1580
|
+
|
|
1581
|
+
"marks[2]": "Attribute marks[2] should have a value between 0 and 100"
|
|
1182
1582
|
|
|
1183
1583
|
}
|
|
1584
|
+
|
|
1184
1585
|
```
|
|
1185
1586
|
|
|
1186
1587
|
## Examples And Usage
|
|
@@ -1193,35 +1594,64 @@ sample-1
|
|
|
1193
1594
|
|
|
1194
1595
|
{
|
|
1195
1596
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1597
|
+
firstName: {
|
|
1598
|
+
|
|
1599
|
+
mandatory: true,
|
|
1600
|
+
|
|
1601
|
+
allowNull: false,
|
|
1602
|
+
|
|
1603
|
+
type: "string",
|
|
1604
|
+
|
|
1605
|
+
minLength: 3,
|
|
1606
|
+
|
|
1607
|
+
minLengthError:"First name must have minimum 3 characters."
|
|
1608
|
+
|
|
1609
|
+
},
|
|
1610
|
+
|
|
1611
|
+
lastName: {
|
|
1612
|
+
|
|
1613
|
+
mandatory: false,
|
|
1614
|
+
|
|
1615
|
+
allowNull: true,
|
|
1616
|
+
|
|
1617
|
+
type: "string",
|
|
1618
|
+
|
|
1619
|
+
},
|
|
1620
|
+
|
|
1621
|
+
email: {
|
|
1622
|
+
|
|
1623
|
+
mandatory: true,
|
|
1624
|
+
|
|
1625
|
+
allowNull: false,
|
|
1626
|
+
|
|
1627
|
+
type: "email",
|
|
1628
|
+
|
|
1629
|
+
},
|
|
1630
|
+
|
|
1631
|
+
phone: {
|
|
1632
|
+
|
|
1633
|
+
mandatory: true,
|
|
1634
|
+
|
|
1635
|
+
allowNull: false,
|
|
1636
|
+
|
|
1637
|
+
type: "string",
|
|
1638
|
+
|
|
1639
|
+
},
|
|
1640
|
+
|
|
1641
|
+
age: {
|
|
1642
|
+
|
|
1643
|
+
mandatory: false,
|
|
1644
|
+
|
|
1645
|
+
type: "number",
|
|
1646
|
+
|
|
1647
|
+
min: 1,
|
|
1648
|
+
|
|
1649
|
+
max: 120,
|
|
1650
|
+
|
|
1651
|
+
},
|
|
1652
|
+
|
|
1224
1653
|
};
|
|
1654
|
+
|
|
1225
1655
|
```
|
|
1226
1656
|
|
|
1227
1657
|
sample-2
|
|
@@ -1229,140 +1659,275 @@ sample-2
|
|
|
1229
1659
|
```javascript
|
|
1230
1660
|
|
|
1231
1661
|
{
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1662
|
+
|
|
1663
|
+
id: {
|
|
1664
|
+
|
|
1665
|
+
mandatory: true,
|
|
1666
|
+
|
|
1667
|
+
allowNull: true,
|
|
1668
|
+
|
|
1669
|
+
type: "uuidv4",
|
|
1670
|
+
|
|
1671
|
+
},
|
|
1672
|
+
|
|
1673
|
+
batchId: {
|
|
1674
|
+
|
|
1675
|
+
mandatory: true,
|
|
1676
|
+
|
|
1677
|
+
allowNull: true,
|
|
1678
|
+
|
|
1679
|
+
type: "objectId",
|
|
1680
|
+
|
|
1681
|
+
},
|
|
1682
|
+
|
|
1683
|
+
firstName: {
|
|
1684
|
+
|
|
1685
|
+
mandatory: true,
|
|
1686
|
+
|
|
1687
|
+
type: "string",
|
|
1688
|
+
|
|
1689
|
+
minLength: 3,
|
|
1690
|
+
|
|
1691
|
+
},
|
|
1692
|
+
|
|
1693
|
+
lastName: {
|
|
1694
|
+
|
|
1695
|
+
mandatory: false,
|
|
1696
|
+
|
|
1697
|
+
allowNull: true,
|
|
1698
|
+
|
|
1699
|
+
type: "string",
|
|
1700
|
+
|
|
1701
|
+
},
|
|
1702
|
+
|
|
1703
|
+
age: {
|
|
1704
|
+
|
|
1705
|
+
type: "number",
|
|
1706
|
+
|
|
1707
|
+
min: 0.1,
|
|
1708
|
+
|
|
1709
|
+
max: 120,
|
|
1710
|
+
|
|
1711
|
+
},
|
|
1712
|
+
|
|
1713
|
+
isAdult: {
|
|
1714
|
+
|
|
1715
|
+
type: "boolean",
|
|
1716
|
+
|
|
1717
|
+
},
|
|
1718
|
+
|
|
1719
|
+
totalWins: {
|
|
1720
|
+
|
|
1721
|
+
type: "number",
|
|
1722
|
+
|
|
1723
|
+
min: 0,
|
|
1724
|
+
|
|
1725
|
+
preventDecimal: true,
|
|
1726
|
+
|
|
1727
|
+
},
|
|
1728
|
+
|
|
1729
|
+
email: {
|
|
1730
|
+
|
|
1731
|
+
regex: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$/,
|
|
1732
|
+
|
|
1733
|
+
},
|
|
1734
|
+
|
|
1735
|
+
githubLink: {
|
|
1736
|
+
|
|
1737
|
+
type: "url",
|
|
1738
|
+
|
|
1739
|
+
},
|
|
1740
|
+
|
|
1741
|
+
accountStatus: {
|
|
1742
|
+
|
|
1743
|
+
type: "enum",
|
|
1744
|
+
|
|
1745
|
+
enumValues: ["Active", "Inactive", 200],
|
|
1746
|
+
|
|
1747
|
+
},
|
|
1748
|
+
|
|
1749
|
+
marks: {
|
|
1750
|
+
|
|
1751
|
+
range: "0-100",
|
|
1752
|
+
|
|
1753
|
+
},
|
|
1754
|
+
|
|
1755
|
+
allMarks: {
|
|
1756
|
+
|
|
1757
|
+
type: "array",
|
|
1758
|
+
|
|
1759
|
+
allowEmptyArray: false,
|
|
1760
|
+
|
|
1761
|
+
elementConstraints: {
|
|
1762
|
+
|
|
1763
|
+
type: "number",
|
|
1764
|
+
|
|
1765
|
+
allowNull: false,
|
|
1766
|
+
|
|
1767
|
+
range: "0-100",
|
|
1768
|
+
|
|
1769
|
+
},
|
|
1770
|
+
|
|
1771
|
+
},
|
|
1772
|
+
|
|
1773
|
+
totalScore: {
|
|
1774
|
+
|
|
1775
|
+
type: "number",
|
|
1776
|
+
|
|
1777
|
+
dependency: {
|
|
1778
|
+
|
|
1779
|
+
result: {
|
|
1780
|
+
|
|
1781
|
+
setDependencyRule: (totalScore, result) => {
|
|
1782
|
+
|
|
1783
|
+
return { mandatory: true, allowNull: false, type: "string" };
|
|
1784
|
+
|
|
1785
|
+
},
|
|
1786
|
+
|
|
1787
|
+
},
|
|
1788
|
+
|
|
1789
|
+
},
|
|
1790
|
+
|
|
1791
|
+
},
|
|
1792
|
+
|
|
1793
|
+
result: {
|
|
1794
|
+
|
|
1795
|
+
type: "string",
|
|
1796
|
+
|
|
1797
|
+
dependency: {
|
|
1798
|
+
|
|
1799
|
+
totalScore: {
|
|
1800
|
+
|
|
1801
|
+
setDependencyRule: (result, totalScore) => {
|
|
1802
|
+
|
|
1803
|
+
return { mandatory: true, allowNull: false, type: "number" };
|
|
1804
|
+
|
|
1805
|
+
},
|
|
1806
|
+
|
|
1807
|
+
},
|
|
1808
|
+
|
|
1809
|
+
},
|
|
1810
|
+
|
|
1811
|
+
},
|
|
1812
|
+
|
|
1813
|
+
minSalary: {
|
|
1814
|
+
|
|
1815
|
+
mandatory: true,
|
|
1816
|
+
|
|
1817
|
+
min: 1,
|
|
1818
|
+
|
|
1819
|
+
type: "number",
|
|
1820
|
+
|
|
1821
|
+
dependency: {
|
|
1822
|
+
|
|
1823
|
+
maxSalary: {
|
|
1824
|
+
|
|
1825
|
+
setDependencyRule: (minSalary, maxSalary) => {
|
|
1826
|
+
|
|
1827
|
+
return {
|
|
1828
|
+
|
|
1829
|
+
mandatory: true,
|
|
1830
|
+
|
|
1831
|
+
min: minSalary + 1,
|
|
1832
|
+
|
|
1833
|
+
minError: "maxSalary must be more than minSalary",
|
|
1834
|
+
|
|
1835
|
+
};
|
|
1836
|
+
|
|
1837
|
+
},
|
|
1838
|
+
|
|
1839
|
+
},
|
|
1840
|
+
|
|
1841
|
+
},
|
|
1842
|
+
|
|
1843
|
+
},
|
|
1844
|
+
|
|
1845
|
+
maxSalary: {
|
|
1846
|
+
|
|
1847
|
+
dependency: {
|
|
1848
|
+
|
|
1849
|
+
minSalary: {
|
|
1850
|
+
|
|
1851
|
+
setDependencyRule: (maxSalary, minSalary) => {
|
|
1852
|
+
|
|
1853
|
+
return {
|
|
1854
|
+
|
|
1855
|
+
mandatory: true,
|
|
1856
|
+
|
|
1857
|
+
max: maxSalary - 1,
|
|
1858
|
+
|
|
1859
|
+
maxError: "minSalary must be less than maxSalary",
|
|
1860
|
+
|
|
1861
|
+
};
|
|
1862
|
+
|
|
1863
|
+
},
|
|
1864
|
+
|
|
1865
|
+
},
|
|
1866
|
+
|
|
1867
|
+
},
|
|
1868
|
+
|
|
1869
|
+
},
|
|
1870
|
+
|
|
1871
|
+
address: {
|
|
1872
|
+
|
|
1873
|
+
mandatory: true,
|
|
1874
|
+
|
|
1875
|
+
type: "object",
|
|
1876
|
+
|
|
1877
|
+
allowEmptyObject: false,
|
|
1878
|
+
|
|
1879
|
+
objectAttr: {
|
|
1880
|
+
|
|
1881
|
+
country: { mandatory: true, type: "string" },
|
|
1882
|
+
|
|
1883
|
+
state: {
|
|
1884
|
+
|
|
1885
|
+
mandatory: true,
|
|
1886
|
+
|
|
1887
|
+
type: "string",
|
|
1888
|
+
|
|
1889
|
+
},
|
|
1890
|
+
|
|
1891
|
+
city: {},
|
|
1892
|
+
|
|
1893
|
+
zip: {
|
|
1894
|
+
|
|
1895
|
+
mandatory: true,
|
|
1896
|
+
|
|
1897
|
+
type: "string",
|
|
1898
|
+
|
|
1899
|
+
},
|
|
1900
|
+
|
|
1901
|
+
position: {
|
|
1902
|
+
|
|
1903
|
+
mandatory: true,
|
|
1904
|
+
|
|
1905
|
+
type: "object",
|
|
1906
|
+
|
|
1907
|
+
allowEmptyObject: false,
|
|
1908
|
+
|
|
1909
|
+
objectAttr: {
|
|
1910
|
+
|
|
1911
|
+
lattitude: { mandatory: true, type: "number" },
|
|
1912
|
+
|
|
1913
|
+
longitude: {
|
|
1914
|
+
|
|
1915
|
+
mandatory: true,
|
|
1916
|
+
|
|
1917
|
+
type: "number",
|
|
1918
|
+
|
|
1919
|
+
},
|
|
1920
|
+
|
|
1921
|
+
},
|
|
1922
|
+
|
|
1923
|
+
},
|
|
1924
|
+
|
|
1925
|
+
},
|
|
1926
|
+
|
|
1927
|
+
},
|
|
1928
|
+
|
|
1365
1929
|
}
|
|
1930
|
+
|
|
1366
1931
|
```
|
|
1367
1932
|
|
|
1368
1933
|
### Usage
|
|
@@ -1371,13 +1936,18 @@ sample-2
|
|
|
1371
1936
|
|
|
1372
1937
|
```javascript
|
|
1373
1938
|
|
|
1374
|
-
|
|
1939
|
+
*//Here validatePayload is your middleware function, where you're invoking perfect payload*
|
|
1375
1940
|
|
|
1376
1941
|
router.post(
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1942
|
+
|
|
1943
|
+
"/payload-validation",
|
|
1944
|
+
|
|
1945
|
+
validatePayload({ rule: <your validation rule json object> }),
|
|
1946
|
+
|
|
1947
|
+
(req, res) => res.send("OK")
|
|
1948
|
+
|
|
1380
1949
|
);
|
|
1950
|
+
|
|
1381
1951
|
```
|
|
1382
1952
|
|
|
1383
1953
|
#### 1 Use perfect-payload in your middleware like below(for MODULE JS)
|
|
@@ -1389,12 +1959,15 @@ export const validatePayload = ({ rule }) => {
|
|
|
1389
1959
|
return (req, res, next) => {
|
|
1390
1960
|
try {
|
|
1391
1961
|
const { statusCode, ...response } = perfectPayloadV1(req?.body, rule);
|
|
1962
|
+
|
|
1392
1963
|
if (+statusCode >= 200 && +statusCode <= 299) {
|
|
1393
1964
|
req.validatedBody = response?.validatedPayload;
|
|
1965
|
+
|
|
1394
1966
|
next();
|
|
1395
1967
|
} else res.status(statusCode).json(response);
|
|
1396
1968
|
} catch (error) {
|
|
1397
1969
|
console.error("Error validating payload", error);
|
|
1970
|
+
|
|
1398
1971
|
res.status(500).json({ error: "Internal Server Error" });
|
|
1399
1972
|
}
|
|
1400
1973
|
};
|
|
@@ -1408,15 +1981,19 @@ function validatePayload({ rule }) {
|
|
|
1408
1981
|
return async (req, res, next) => {
|
|
1409
1982
|
try {
|
|
1410
1983
|
const { perfectPayloadV1 } = await import("perfect-payload");
|
|
1984
|
+
|
|
1411
1985
|
const { statusCode, ...response } = perfectPayloadV1(req?.body, rule);
|
|
1986
|
+
|
|
1412
1987
|
if (+statusCode >= 200 && +statusCode <= 299) {
|
|
1413
1988
|
req.validatedBody = response?.validatedPayload;
|
|
1989
|
+
|
|
1414
1990
|
next();
|
|
1415
1991
|
} else {
|
|
1416
1992
|
res.status(statusCode).json(response);
|
|
1417
1993
|
}
|
|
1418
1994
|
} catch (error) {
|
|
1419
1995
|
console.error("Error validating payload", error);
|
|
1996
|
+
|
|
1420
1997
|
res.status(500).json({ error: "Internal Server Error" });
|
|
1421
1998
|
}
|
|
1422
1999
|
};
|
|
@@ -1425,8 +2002,10 @@ function validatePayload({ rule }) {
|
|
|
1425
2002
|
module.exports = { validatePayload };
|
|
1426
2003
|
```
|
|
1427
2004
|
|
|
1428
|
-
|
|
2005
|
+
**---**
|
|
1429
2006
|
|
|
1430
2007
|
This documentation provides a comprehensive guide to using the data
|
|
2008
|
+
|
|
1431
2009
|
validation module effectively. Ensure to define your validation rules
|
|
2010
|
+
|
|
1432
2011
|
clearly to maintain data quality and consistency in your applications.
|