perfect-payload 1.2.0 → 1.2.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 +3 -434
- package/package.json +14 -6
package/README.md
CHANGED
|
@@ -19,30 +19,24 @@ import { perfectPayload } from "perfect-payload";
|
|
|
19
19
|
|
|
20
20
|
const payload = {
|
|
21
21
|
name: "Kiran",
|
|
22
|
-
|
|
23
22
|
email: "kiran@example.com",
|
|
24
|
-
|
|
25
23
|
age: 29,
|
|
26
24
|
};
|
|
27
25
|
|
|
28
26
|
const validationRules = {
|
|
29
27
|
name: {
|
|
30
28
|
mandatory: true,
|
|
31
|
-
|
|
32
29
|
type: "string",
|
|
33
30
|
},
|
|
34
31
|
|
|
35
32
|
email: {
|
|
36
33
|
mandatory: true,
|
|
37
|
-
|
|
38
34
|
type: "email",
|
|
39
35
|
},
|
|
40
36
|
|
|
41
37
|
age: {
|
|
42
38
|
mandatory: true,
|
|
43
|
-
|
|
44
39
|
type: "number",
|
|
45
|
-
|
|
46
40
|
min: 18,
|
|
47
41
|
},
|
|
48
42
|
};
|
|
@@ -57,21 +51,13 @@ console.log(result);
|
|
|
57
51
|
```js
|
|
58
52
|
|
|
59
53
|
{
|
|
60
|
-
|
|
61
54
|
statusCode: 200,
|
|
62
|
-
|
|
63
55
|
valid: true,
|
|
64
|
-
|
|
65
56
|
validatedPayload: {
|
|
66
|
-
|
|
67
57
|
name: "Kiran",
|
|
68
|
-
|
|
69
58
|
email: "kiran@example.com",
|
|
70
|
-
|
|
71
59
|
age: 29
|
|
72
|
-
|
|
73
60
|
}
|
|
74
|
-
|
|
75
61
|
}
|
|
76
62
|
```
|
|
77
63
|
|
|
@@ -85,27 +71,16 @@ to safely overwrite request.body or assign it to a new request property
|
|
|
85
71
|
```js
|
|
86
72
|
|
|
87
73
|
{
|
|
88
|
-
|
|
89
74
|
statusCode: 400,
|
|
90
|
-
|
|
91
75
|
valid: false,
|
|
92
|
-
|
|
93
76
|
message: "One or more attribute values are invalid",
|
|
94
|
-
|
|
95
77
|
errors: [
|
|
96
|
-
|
|
97
78
|
{
|
|
98
|
-
|
|
99
79
|
path: "email",
|
|
100
|
-
|
|
101
80
|
code: "INVALID_EMAIL",
|
|
102
|
-
|
|
103
81
|
message: "Invalid email format for attribute email"
|
|
104
|
-
|
|
105
82
|
}
|
|
106
|
-
|
|
107
83
|
]
|
|
108
|
-
|
|
109
84
|
}
|
|
110
85
|
```
|
|
111
86
|
|
|
@@ -114,13 +89,9 @@ Each error returned by `perfectPayload()` contains:
|
|
|
114
89
|
```js
|
|
115
90
|
|
|
116
91
|
{
|
|
117
|
-
|
|
118
92
|
path: "field.path",
|
|
119
|
-
|
|
120
93
|
code: "ERROR_CODE",
|
|
121
|
-
|
|
122
94
|
message: "Human readable validation message"
|
|
123
|
-
|
|
124
95
|
}
|
|
125
96
|
```
|
|
126
97
|
|
|
@@ -160,9 +131,7 @@ while the new `perfectPayload()` API returns structured errors:
|
|
|
160
131
|
errors: [
|
|
161
132
|
{
|
|
162
133
|
path: "email",
|
|
163
|
-
|
|
164
134
|
code: "INVALID_EMAIL",
|
|
165
|
-
|
|
166
135
|
message: "Invalid email format for attribute email",
|
|
167
136
|
},
|
|
168
137
|
];
|
|
@@ -227,7 +196,6 @@ Example:
|
|
|
227
196
|
const rules = {
|
|
228
197
|
address: {
|
|
229
198
|
type: "object",
|
|
230
|
-
|
|
231
199
|
allowEmptyObject: false,
|
|
232
200
|
},
|
|
233
201
|
};
|
|
@@ -249,7 +217,6 @@ Example:
|
|
|
249
217
|
const rules = {
|
|
250
218
|
products: {
|
|
251
219
|
type: "array",
|
|
252
|
-
|
|
253
220
|
allowEmptyArray: false,
|
|
254
221
|
},
|
|
255
222
|
};
|
|
@@ -268,31 +235,18 @@ Supported values:
|
|
|
268
235
|
```text
|
|
269
236
|
|
|
270
237
|
number
|
|
271
|
-
|
|
272
238
|
string
|
|
273
|
-
|
|
274
239
|
boolean
|
|
275
|
-
|
|
276
240
|
email
|
|
277
|
-
|
|
278
241
|
url
|
|
279
|
-
|
|
280
242
|
enum
|
|
281
|
-
|
|
282
243
|
uuid
|
|
283
|
-
|
|
284
244
|
uuidv1
|
|
285
|
-
|
|
286
245
|
uuidv3
|
|
287
|
-
|
|
288
246
|
uuidv4
|
|
289
|
-
|
|
290
247
|
uuidv5
|
|
291
|
-
|
|
292
248
|
objectId
|
|
293
|
-
|
|
294
249
|
array
|
|
295
|
-
|
|
296
250
|
object
|
|
297
251
|
```
|
|
298
252
|
|
|
@@ -303,11 +257,9 @@ const rules = {
|
|
|
303
257
|
age: {
|
|
304
258
|
type: "number",
|
|
305
259
|
},
|
|
306
|
-
|
|
307
260
|
email: {
|
|
308
261
|
type: "email",
|
|
309
262
|
},
|
|
310
|
-
|
|
311
263
|
active: {
|
|
312
264
|
type: "boolean",
|
|
313
265
|
},
|
|
@@ -328,7 +280,6 @@ Example:
|
|
|
328
280
|
const rules = {
|
|
329
281
|
status: {
|
|
330
282
|
type: "enum",
|
|
331
|
-
|
|
332
283
|
enumValues: ["active", "inactive", "blocked", 1, 0],
|
|
333
284
|
},
|
|
334
285
|
};
|
|
@@ -348,7 +299,6 @@ Example:
|
|
|
348
299
|
const rules = {
|
|
349
300
|
status: {
|
|
350
301
|
type: "enum",
|
|
351
|
-
|
|
352
302
|
enumValues: ["active", "inactive", "blocked"],
|
|
353
303
|
},
|
|
354
304
|
};
|
|
@@ -361,23 +311,14 @@ Possible error codes for types:
|
|
|
361
311
|
```text
|
|
362
312
|
|
|
363
313
|
INVALID_TYPE
|
|
364
|
-
|
|
365
314
|
INVALID_EMAIL
|
|
366
|
-
|
|
367
315
|
INVALID_URL
|
|
368
|
-
|
|
369
316
|
INVALID_ENUM
|
|
370
|
-
|
|
371
317
|
INVALID_UUID
|
|
372
|
-
|
|
373
318
|
INVALID_UUID_V1
|
|
374
|
-
|
|
375
319
|
INVALID_UUID_V3
|
|
376
|
-
|
|
377
320
|
INVALID_UUID_V4
|
|
378
|
-
|
|
379
321
|
INVALID_UUID_V5
|
|
380
|
-
|
|
381
322
|
INVALID_OBJECT_ID
|
|
382
323
|
```
|
|
383
324
|
|
|
@@ -395,7 +336,6 @@ Example:
|
|
|
395
336
|
const rules = {
|
|
396
337
|
employeeCode: {
|
|
397
338
|
type: "string",
|
|
398
|
-
|
|
399
339
|
regex: /^[A-Z]{3}[0-9]{3}$/,
|
|
400
340
|
},
|
|
401
341
|
};
|
|
@@ -417,7 +357,6 @@ Example:
|
|
|
417
357
|
const rules = {
|
|
418
358
|
username: {
|
|
419
359
|
type: "string",
|
|
420
|
-
|
|
421
360
|
minLength: 5,
|
|
422
361
|
},
|
|
423
362
|
};
|
|
@@ -439,7 +378,6 @@ Example:
|
|
|
439
378
|
const rules = {
|
|
440
379
|
username: {
|
|
441
380
|
type: "string",
|
|
442
|
-
|
|
443
381
|
maxLength: 20,
|
|
444
382
|
},
|
|
445
383
|
};
|
|
@@ -461,7 +399,6 @@ Example:
|
|
|
461
399
|
const rules = {
|
|
462
400
|
quantity: {
|
|
463
401
|
type: "number",
|
|
464
|
-
|
|
465
402
|
preventDecimal: true,
|
|
466
403
|
},
|
|
467
404
|
};
|
|
@@ -483,7 +420,6 @@ Example:
|
|
|
483
420
|
const rules = {
|
|
484
421
|
age: {
|
|
485
422
|
type: "number",
|
|
486
|
-
|
|
487
423
|
min: 18,
|
|
488
424
|
},
|
|
489
425
|
};
|
|
@@ -505,7 +441,6 @@ Example:
|
|
|
505
441
|
const rules = {
|
|
506
442
|
quantity: {
|
|
507
443
|
type: "number",
|
|
508
|
-
|
|
509
444
|
max: 100,
|
|
510
445
|
},
|
|
511
446
|
};
|
|
@@ -527,7 +462,6 @@ Example:
|
|
|
527
462
|
const rules = {
|
|
528
463
|
marks: {
|
|
529
464
|
type: "number",
|
|
530
|
-
|
|
531
465
|
range: "0-100",
|
|
532
466
|
},
|
|
533
467
|
};
|
|
@@ -547,10 +481,8 @@ Example:
|
|
|
547
481
|
const rules = {
|
|
548
482
|
marks: {
|
|
549
483
|
type: "array",
|
|
550
|
-
|
|
551
484
|
elementConstraints: {
|
|
552
485
|
type: "number",
|
|
553
|
-
|
|
554
486
|
range: "0-100",
|
|
555
487
|
},
|
|
556
488
|
},
|
|
@@ -564,13 +496,9 @@ Example error:
|
|
|
564
496
|
{
|
|
565
497
|
|
|
566
498
|
path: "marks[2]",
|
|
567
|
-
|
|
568
499
|
code: "OUT_OF_RANGE",
|
|
569
|
-
|
|
570
500
|
message:
|
|
571
|
-
|
|
572
501
|
"Attribute marks[2] should have a value between 0 and 100"
|
|
573
|
-
|
|
574
502
|
}
|
|
575
503
|
```
|
|
576
504
|
|
|
@@ -583,11 +511,9 @@ Example:
|
|
|
583
511
|
const rules = {
|
|
584
512
|
marks: {
|
|
585
513
|
type: "array",
|
|
586
|
-
|
|
587
514
|
elementConstraints: {
|
|
588
515
|
type: "number",
|
|
589
516
|
},
|
|
590
|
-
|
|
591
517
|
elementConstraintsError: "Every marks element must be a number",
|
|
592
518
|
},
|
|
593
519
|
};
|
|
@@ -605,22 +531,17 @@ Example:
|
|
|
605
531
|
const rules = {
|
|
606
532
|
address: {
|
|
607
533
|
type: "object",
|
|
608
|
-
|
|
609
534
|
objectAttr: {
|
|
610
535
|
city: {
|
|
611
536
|
mandatory: true,
|
|
612
|
-
|
|
613
537
|
type: "string",
|
|
614
538
|
},
|
|
615
|
-
|
|
616
539
|
location: {
|
|
617
540
|
type: "object",
|
|
618
|
-
|
|
619
541
|
objectAttr: {
|
|
620
542
|
latitude: {
|
|
621
543
|
type: "number",
|
|
622
544
|
},
|
|
623
|
-
|
|
624
545
|
longitude: {
|
|
625
546
|
type: "number",
|
|
626
547
|
},
|
|
@@ -636,15 +557,10 @@ Nested errors include the complete field path:
|
|
|
636
557
|
```js
|
|
637
558
|
|
|
638
559
|
{
|
|
639
|
-
|
|
640
560
|
path: "address.location.latitude",
|
|
641
|
-
|
|
642
561
|
code: "INVALID_TYPE",
|
|
643
|
-
|
|
644
562
|
message:
|
|
645
|
-
|
|
646
563
|
"Invalid type for attribute address.location.latitude, required number value"
|
|
647
|
-
|
|
648
564
|
}
|
|
649
565
|
```
|
|
650
566
|
|
|
@@ -660,14 +576,11 @@ Example:
|
|
|
660
576
|
const rules = {
|
|
661
577
|
minSalary: {
|
|
662
578
|
type: "number",
|
|
663
|
-
|
|
664
579
|
dependency: {
|
|
665
580
|
maxSalary: {
|
|
666
581
|
setDependencyRule: (minSalary, maxSalary) => ({
|
|
667
582
|
type: "number",
|
|
668
|
-
|
|
669
583
|
min: minSalary + 1,
|
|
670
|
-
|
|
671
584
|
minError: "maxSalary must be more than minSalary",
|
|
672
585
|
}),
|
|
673
586
|
},
|
|
@@ -683,13 +596,9 @@ Example error:
|
|
|
683
596
|
{
|
|
684
597
|
|
|
685
598
|
path: "maxSalary",
|
|
686
|
-
|
|
687
599
|
code: "MIN_VALUE",
|
|
688
|
-
|
|
689
600
|
message:
|
|
690
|
-
|
|
691
601
|
"maxSalary must be more than minSalary"
|
|
692
|
-
|
|
693
602
|
}
|
|
694
603
|
```
|
|
695
604
|
|
|
@@ -701,47 +610,26 @@ validation error codes:
|
|
|
701
610
|
```text
|
|
702
611
|
|
|
703
612
|
REQUIRED
|
|
704
|
-
|
|
705
613
|
NULL_NOT_ALLOWED
|
|
706
|
-
|
|
707
614
|
EMPTY_OBJECT_NOT_ALLOWED
|
|
708
|
-
|
|
709
615
|
EMPTY_ARRAY_NOT_ALLOWED
|
|
710
|
-
|
|
711
616
|
INVALID_ARRAY_ELEMENT
|
|
712
|
-
|
|
713
617
|
REGEX_MISMATCH
|
|
714
|
-
|
|
715
618
|
INVALID_TYPE
|
|
716
|
-
|
|
717
619
|
INVALID_EMAIL
|
|
718
|
-
|
|
719
620
|
INVALID_URL
|
|
720
|
-
|
|
721
621
|
INVALID_ENUM
|
|
722
|
-
|
|
723
622
|
INVALID_UUID
|
|
724
|
-
|
|
725
623
|
INVALID_UUID_V1
|
|
726
|
-
|
|
727
624
|
INVALID_UUID_V3
|
|
728
|
-
|
|
729
625
|
INVALID_UUID_V4
|
|
730
|
-
|
|
731
626
|
INVALID_UUID_V5
|
|
732
|
-
|
|
733
627
|
INVALID_OBJECT_ID
|
|
734
|
-
|
|
735
628
|
MIN_LENGTH
|
|
736
|
-
|
|
737
629
|
MAX_LENGTH
|
|
738
|
-
|
|
739
630
|
DECIMAL_NOT_ALLOWED
|
|
740
|
-
|
|
741
631
|
MIN_VALUE
|
|
742
|
-
|
|
743
632
|
MAX_VALUE
|
|
744
|
-
|
|
745
633
|
OUT_OF_RANGE
|
|
746
634
|
```
|
|
747
635
|
|
|
@@ -774,13 +662,9 @@ keeping the same structured error format:
|
|
|
774
662
|
```js
|
|
775
663
|
|
|
776
664
|
{
|
|
777
|
-
|
|
778
665
|
path: "email",
|
|
779
|
-
|
|
780
666
|
code: "INVALID_EMAIL",
|
|
781
|
-
|
|
782
667
|
message: "Email address is invalid"
|
|
783
|
-
|
|
784
668
|
}
|
|
785
669
|
```
|
|
786
670
|
|
|
@@ -790,11 +674,8 @@ Example:
|
|
|
790
674
|
const rules = {
|
|
791
675
|
email: {
|
|
792
676
|
mandatory: true,
|
|
793
|
-
|
|
794
677
|
type: "email",
|
|
795
|
-
|
|
796
678
|
mandatoryError: "Email is required",
|
|
797
|
-
|
|
798
679
|
typeError: "Email address is invalid",
|
|
799
680
|
},
|
|
800
681
|
};
|
|
@@ -805,13 +686,9 @@ If `email` is missing:
|
|
|
805
686
|
```js
|
|
806
687
|
|
|
807
688
|
{
|
|
808
|
-
|
|
809
689
|
path: "email",
|
|
810
|
-
|
|
811
690
|
code: "REQUIRED",
|
|
812
|
-
|
|
813
691
|
message: "Email is required"
|
|
814
|
-
|
|
815
692
|
}
|
|
816
693
|
```
|
|
817
694
|
|
|
@@ -820,13 +697,9 @@ If `email` is present but invalid:
|
|
|
820
697
|
```js
|
|
821
698
|
|
|
822
699
|
{
|
|
823
|
-
|
|
824
700
|
path: "email",
|
|
825
|
-
|
|
826
701
|
code: "INVALID_EMAIL",
|
|
827
|
-
|
|
828
702
|
message: "Email address is invalid"
|
|
829
|
-
|
|
830
703
|
}
|
|
831
704
|
```
|
|
832
705
|
|
|
@@ -867,40 +740,27 @@ If `email` is present but invalid:
|
|
|
867
740
|
```js
|
|
868
741
|
const payload = {
|
|
869
742
|
username: "ab",
|
|
870
|
-
|
|
871
743
|
age: 15,
|
|
872
|
-
|
|
873
744
|
score: 120,
|
|
874
745
|
};
|
|
875
746
|
|
|
876
747
|
const rules = {
|
|
877
748
|
username: {
|
|
878
749
|
mandatory: true,
|
|
879
|
-
|
|
880
750
|
type: "string",
|
|
881
|
-
|
|
882
751
|
minLength: 3,
|
|
883
|
-
|
|
884
752
|
mandatoryError: "Username is required",
|
|
885
|
-
|
|
886
753
|
typeError: "Username must be a string",
|
|
887
|
-
|
|
888
754
|
minLengthError: "Username must contain at least 3 characters",
|
|
889
755
|
},
|
|
890
|
-
|
|
891
756
|
age: {
|
|
892
757
|
type: "number",
|
|
893
|
-
|
|
894
758
|
min: 18,
|
|
895
|
-
|
|
896
759
|
minError: "Age must be at least 18",
|
|
897
760
|
},
|
|
898
|
-
|
|
899
761
|
score: {
|
|
900
762
|
type: "number",
|
|
901
|
-
|
|
902
763
|
range: "0-100",
|
|
903
|
-
|
|
904
764
|
rangeError: "Score must be between 0 and 100",
|
|
905
765
|
},
|
|
906
766
|
};
|
|
@@ -913,55 +773,30 @@ Example result:
|
|
|
913
773
|
```js
|
|
914
774
|
|
|
915
775
|
{
|
|
916
|
-
|
|
917
776
|
statusCode: 400,
|
|
918
|
-
|
|
919
777
|
valid: false,
|
|
920
|
-
|
|
921
778
|
message:
|
|
922
|
-
|
|
923
779
|
"One or more attribute values are invalid",
|
|
924
|
-
|
|
925
780
|
errors: [
|
|
926
|
-
|
|
927
781
|
{
|
|
928
|
-
|
|
929
782
|
path: "username",
|
|
930
|
-
|
|
931
783
|
code: "MIN_LENGTH",
|
|
932
|
-
|
|
933
784
|
message:
|
|
934
|
-
|
|
935
785
|
"Username must contain at least 3 characters"
|
|
936
|
-
|
|
937
786
|
},
|
|
938
|
-
|
|
939
787
|
{
|
|
940
|
-
|
|
941
788
|
path: "age",
|
|
942
|
-
|
|
943
789
|
code: "MIN_VALUE",
|
|
944
|
-
|
|
945
790
|
message:
|
|
946
|
-
|
|
947
791
|
"Age must be at least 18"
|
|
948
|
-
|
|
949
792
|
},
|
|
950
|
-
|
|
951
793
|
{
|
|
952
|
-
|
|
953
794
|
path: "score",
|
|
954
|
-
|
|
955
795
|
code: "OUT_OF_RANGE",
|
|
956
|
-
|
|
957
796
|
message:
|
|
958
|
-
|
|
959
797
|
"Score must be between 0 and 100"
|
|
960
|
-
|
|
961
798
|
}
|
|
962
|
-
|
|
963
799
|
]
|
|
964
|
-
|
|
965
800
|
}
|
|
966
801
|
```
|
|
967
802
|
|
|
@@ -977,9 +812,7 @@ For example:
|
|
|
977
812
|
const rules = {
|
|
978
813
|
age: {
|
|
979
814
|
type: "number",
|
|
980
|
-
|
|
981
815
|
min: 18,
|
|
982
|
-
|
|
983
816
|
minError: "You must be 18 or older",
|
|
984
817
|
},
|
|
985
818
|
};
|
|
@@ -990,13 +823,9 @@ Still returns:
|
|
|
990
823
|
```js
|
|
991
824
|
|
|
992
825
|
{
|
|
993
|
-
|
|
994
826
|
path: "age",
|
|
995
|
-
|
|
996
827
|
code: "MIN_VALUE",
|
|
997
|
-
|
|
998
828
|
message: "You must be 18 or older"
|
|
999
|
-
|
|
1000
829
|
}
|
|
1001
830
|
```
|
|
1002
831
|
|
|
@@ -1023,9 +852,7 @@ Example:
|
|
|
1023
852
|
```js
|
|
1024
853
|
const customValidResponse = {
|
|
1025
854
|
statusCode: 201,
|
|
1026
|
-
|
|
1027
855
|
valid: true,
|
|
1028
|
-
|
|
1029
856
|
message: "Payload validated successfully",
|
|
1030
857
|
};
|
|
1031
858
|
|
|
@@ -1037,23 +864,14 @@ When validation succeeds, `validatedPayload` is automatically added:
|
|
|
1037
864
|
```js
|
|
1038
865
|
|
|
1039
866
|
{
|
|
1040
|
-
|
|
1041
867
|
statusCode: 201,
|
|
1042
|
-
|
|
1043
868
|
valid: true,
|
|
1044
|
-
|
|
1045
869
|
message: "Payload validated successfully",
|
|
1046
|
-
|
|
1047
870
|
validatedPayload: {
|
|
1048
|
-
|
|
1049
871
|
name: "Kiran",
|
|
1050
|
-
|
|
1051
872
|
email: "kiran@example.com",
|
|
1052
|
-
|
|
1053
873
|
age: 29
|
|
1054
|
-
|
|
1055
874
|
}
|
|
1056
|
-
|
|
1057
875
|
}
|
|
1058
876
|
```
|
|
1059
877
|
|
|
@@ -1064,19 +882,14 @@ Example:
|
|
|
1064
882
|
```js
|
|
1065
883
|
const customInvalidResponse = {
|
|
1066
884
|
statusCode: 422,
|
|
1067
|
-
|
|
1068
885
|
valid: false,
|
|
1069
|
-
|
|
1070
886
|
message: "Payload validation failed",
|
|
1071
887
|
};
|
|
1072
888
|
|
|
1073
889
|
const result = perfectPayload(
|
|
1074
890
|
payload,
|
|
1075
|
-
|
|
1076
891
|
validationRules,
|
|
1077
|
-
|
|
1078
892
|
undefined,
|
|
1079
|
-
|
|
1080
893
|
customInvalidResponse,
|
|
1081
894
|
);
|
|
1082
895
|
```
|
|
@@ -1088,27 +901,16 @@ When validation fails, `errors` is automatically added:
|
|
|
1088
901
|
{
|
|
1089
902
|
|
|
1090
903
|
statusCode: 422,
|
|
1091
|
-
|
|
1092
904
|
valid: false,
|
|
1093
|
-
|
|
1094
905
|
message: "Payload validation failed",
|
|
1095
|
-
|
|
1096
906
|
errors: [
|
|
1097
|
-
|
|
1098
907
|
{
|
|
1099
|
-
|
|
1100
908
|
path: "email",
|
|
1101
|
-
|
|
1102
909
|
code: "INVALID_EMAIL",
|
|
1103
|
-
|
|
1104
910
|
message:
|
|
1105
|
-
|
|
1106
911
|
"Invalid email format for attribute email"
|
|
1107
|
-
|
|
1108
912
|
}
|
|
1109
|
-
|
|
1110
913
|
]
|
|
1111
|
-
|
|
1112
914
|
}
|
|
1113
915
|
```
|
|
1114
916
|
|
|
@@ -1117,27 +919,20 @@ When validation fails, `errors` is automatically added:
|
|
|
1117
919
|
```js
|
|
1118
920
|
const customValidResponse = {
|
|
1119
921
|
statusCode: 201,
|
|
1120
|
-
|
|
1121
922
|
valid: true,
|
|
1122
|
-
|
|
1123
923
|
message: "CUSTOM_VALID_RESPONSE",
|
|
1124
924
|
};
|
|
1125
925
|
|
|
1126
926
|
const customInvalidResponse = {
|
|
1127
927
|
statusCode: 422,
|
|
1128
|
-
|
|
1129
928
|
valid: false,
|
|
1130
|
-
|
|
1131
929
|
message: "CUSTOM_INVALID_RESPONSE",
|
|
1132
930
|
};
|
|
1133
931
|
|
|
1134
932
|
const result = perfectPayload(
|
|
1135
933
|
payload,
|
|
1136
|
-
|
|
1137
934
|
validationRules,
|
|
1138
|
-
|
|
1139
935
|
customValidResponse,
|
|
1140
|
-
|
|
1141
936
|
customInvalidResponse,
|
|
1142
937
|
);
|
|
1143
938
|
```
|
|
@@ -1167,17 +962,11 @@ is:
|
|
|
1167
962
|
```js
|
|
1168
963
|
|
|
1169
964
|
{
|
|
1170
|
-
|
|
1171
965
|
statusCode: 200,
|
|
1172
|
-
|
|
1173
966
|
valid: true,
|
|
1174
|
-
|
|
1175
967
|
validatedPayload: {
|
|
1176
|
-
|
|
1177
968
|
// validated fields
|
|
1178
|
-
|
|
1179
969
|
}
|
|
1180
|
-
|
|
1181
970
|
}
|
|
1182
971
|
```
|
|
1183
972
|
|
|
@@ -1186,27 +975,16 @@ The default invalid response is:
|
|
|
1186
975
|
```js
|
|
1187
976
|
|
|
1188
977
|
{
|
|
1189
|
-
|
|
1190
978
|
statusCode: 400,
|
|
1191
|
-
|
|
1192
979
|
valid: false,
|
|
1193
|
-
|
|
1194
980
|
message: "One or more attribute values are invalid",
|
|
1195
|
-
|
|
1196
981
|
errors: [
|
|
1197
|
-
|
|
1198
982
|
{
|
|
1199
|
-
|
|
1200
983
|
path: "field",
|
|
1201
|
-
|
|
1202
984
|
code: "ERROR_CODE",
|
|
1203
|
-
|
|
1204
985
|
message: "Validation error message"
|
|
1205
|
-
|
|
1206
986
|
}
|
|
1207
|
-
|
|
1208
987
|
]
|
|
1209
|
-
|
|
1210
988
|
}
|
|
1211
989
|
```
|
|
1212
990
|
|
|
@@ -1233,13 +1011,9 @@ An error can be returned as:
|
|
|
1233
1011
|
```js
|
|
1234
1012
|
|
|
1235
1013
|
{
|
|
1236
|
-
|
|
1237
1014
|
path: "email",
|
|
1238
|
-
|
|
1239
1015
|
code: "INVALID_EMAIL",
|
|
1240
|
-
|
|
1241
1016
|
message: "Invalid email format for attribute email"
|
|
1242
|
-
|
|
1243
1017
|
}
|
|
1244
1018
|
```
|
|
1245
1019
|
|
|
@@ -1251,10 +1025,8 @@ Use `objectAttr` to validate properties inside an object.
|
|
|
1251
1025
|
const payload = {
|
|
1252
1026
|
address: {
|
|
1253
1027
|
city: "Bengaluru",
|
|
1254
|
-
|
|
1255
1028
|
location: {
|
|
1256
1029
|
latitude: "12.9716",
|
|
1257
|
-
|
|
1258
1030
|
longitude: 77.5946,
|
|
1259
1031
|
},
|
|
1260
1032
|
},
|
|
@@ -1263,20 +1035,16 @@ const payload = {
|
|
|
1263
1035
|
const rules = {
|
|
1264
1036
|
address: {
|
|
1265
1037
|
type: "object",
|
|
1266
|
-
|
|
1267
1038
|
objectAttr: {
|
|
1268
1039
|
city: {
|
|
1269
1040
|
type: "string",
|
|
1270
1041
|
},
|
|
1271
|
-
|
|
1272
1042
|
location: {
|
|
1273
1043
|
type: "object",
|
|
1274
|
-
|
|
1275
1044
|
objectAttr: {
|
|
1276
1045
|
latitude: {
|
|
1277
1046
|
type: "number",
|
|
1278
1047
|
},
|
|
1279
|
-
|
|
1280
1048
|
longitude: {
|
|
1281
1049
|
type: "number",
|
|
1282
1050
|
},
|
|
@@ -1295,15 +1063,10 @@ its complete nested path:
|
|
|
1295
1063
|
```js
|
|
1296
1064
|
|
|
1297
1065
|
{
|
|
1298
|
-
|
|
1299
1066
|
path: "address.location.latitude",
|
|
1300
|
-
|
|
1301
1067
|
code: "INVALID_TYPE",
|
|
1302
|
-
|
|
1303
1068
|
message:
|
|
1304
|
-
|
|
1305
1069
|
"Invalid type for attribute address.location.latitude, required number value"
|
|
1306
|
-
|
|
1307
1070
|
}
|
|
1308
1071
|
```
|
|
1309
1072
|
|
|
@@ -1312,9 +1075,7 @@ Nested paths use dot notation:
|
|
|
1312
1075
|
```text
|
|
1313
1076
|
|
|
1314
1077
|
address.city
|
|
1315
|
-
|
|
1316
1078
|
address.location.latitude
|
|
1317
|
-
|
|
1318
1079
|
address.location.longitude
|
|
1319
1080
|
```
|
|
1320
1081
|
|
|
@@ -1331,10 +1092,8 @@ const payload = {
|
|
|
1331
1092
|
const rules = {
|
|
1332
1093
|
marks: {
|
|
1333
1094
|
type: "array",
|
|
1334
|
-
|
|
1335
1095
|
elementConstraints: {
|
|
1336
1096
|
type: "number",
|
|
1337
|
-
|
|
1338
1097
|
range: "0-100",
|
|
1339
1098
|
},
|
|
1340
1099
|
},
|
|
@@ -1348,15 +1107,10 @@ The invalid third element is reported as:
|
|
|
1348
1107
|
```js
|
|
1349
1108
|
|
|
1350
1109
|
{
|
|
1351
|
-
|
|
1352
1110
|
path: "marks[2]",
|
|
1353
|
-
|
|
1354
1111
|
code: "OUT_OF_RANGE",
|
|
1355
|
-
|
|
1356
1112
|
message:
|
|
1357
|
-
|
|
1358
1113
|
"Attribute marks[2] should have a value between 0 and 100"
|
|
1359
|
-
|
|
1360
1114
|
}
|
|
1361
1115
|
```
|
|
1362
1116
|
|
|
@@ -1365,9 +1119,7 @@ Array paths use zero-based indexes:
|
|
|
1365
1119
|
```text
|
|
1366
1120
|
|
|
1367
1121
|
marks[0]
|
|
1368
|
-
|
|
1369
1122
|
marks[1]
|
|
1370
|
-
|
|
1371
1123
|
marks[2]
|
|
1372
1124
|
```
|
|
1373
1125
|
|
|
@@ -1380,9 +1132,7 @@ For example:
|
|
|
1380
1132
|
```text
|
|
1381
1133
|
|
|
1382
1134
|
products[0].quantity
|
|
1383
|
-
|
|
1384
1135
|
products[1].quantity
|
|
1385
|
-
|
|
1386
1136
|
products[2].price
|
|
1387
1137
|
```
|
|
1388
1138
|
|
|
@@ -1426,17 +1176,9 @@ Result:
|
|
|
1426
1176
|
|
|
1427
1177
|
{
|
|
1428
1178
|
|
|
1429
|
-
"email":
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
"address.location.latitude":
|
|
1434
|
-
|
|
1435
|
-
"Invalid type for attribute address.location.latitude, required number value",
|
|
1436
|
-
|
|
1437
|
-
"marks[2]":
|
|
1438
|
-
|
|
1439
|
-
"Attribute marks[2] should have a value between 0 and 100"
|
|
1179
|
+
"email": "Invalid email format for attribute email",
|
|
1180
|
+
"address.location.latitude": "Invalid type for attribute address.location.latitude, required number value",
|
|
1181
|
+
"marks[2]": "Attribute marks[2] should have a value between 0 and 100"
|
|
1440
1182
|
|
|
1441
1183
|
}
|
|
1442
1184
|
```
|
|
@@ -1452,61 +1194,33 @@ sample-1
|
|
|
1452
1194
|
{
|
|
1453
1195
|
|
|
1454
1196
|
firstName: {
|
|
1455
|
-
|
|
1456
1197
|
mandatory: true,
|
|
1457
|
-
|
|
1458
1198
|
allowNull: false,
|
|
1459
|
-
|
|
1460
1199
|
type: "string",
|
|
1461
|
-
|
|
1462
1200
|
minLength: 3,
|
|
1463
|
-
|
|
1464
1201
|
minLengthError:"First name must have minimum 3 characters."
|
|
1465
|
-
|
|
1466
1202
|
},
|
|
1467
|
-
|
|
1468
1203
|
lastName: {
|
|
1469
|
-
|
|
1470
1204
|
mandatory: false,
|
|
1471
|
-
|
|
1472
1205
|
allowNull: true,
|
|
1473
|
-
|
|
1474
1206
|
type: "string",
|
|
1475
|
-
|
|
1476
1207
|
},
|
|
1477
|
-
|
|
1478
1208
|
email: {
|
|
1479
|
-
|
|
1480
1209
|
mandatory: true,
|
|
1481
|
-
|
|
1482
1210
|
allowNull: false,
|
|
1483
|
-
|
|
1484
1211
|
type: "email",
|
|
1485
|
-
|
|
1486
1212
|
},
|
|
1487
|
-
|
|
1488
1213
|
phone: {
|
|
1489
|
-
|
|
1490
1214
|
mandatory: true,
|
|
1491
|
-
|
|
1492
1215
|
allowNull: false,
|
|
1493
|
-
|
|
1494
1216
|
type: "string",
|
|
1495
|
-
|
|
1496
1217
|
},
|
|
1497
|
-
|
|
1498
1218
|
age: {
|
|
1499
|
-
|
|
1500
1219
|
mandatory: false,
|
|
1501
|
-
|
|
1502
1220
|
type: "number",
|
|
1503
|
-
|
|
1504
1221
|
min: 1,
|
|
1505
|
-
|
|
1506
1222
|
max: 120,
|
|
1507
|
-
|
|
1508
1223
|
},
|
|
1509
|
-
|
|
1510
1224
|
};
|
|
1511
1225
|
```
|
|
1512
1226
|
|
|
@@ -1515,273 +1229,139 @@ sample-2
|
|
|
1515
1229
|
```javascript
|
|
1516
1230
|
|
|
1517
1231
|
{
|
|
1518
|
-
|
|
1519
1232
|
id: {
|
|
1520
|
-
|
|
1521
1233
|
mandatory: true,
|
|
1522
|
-
|
|
1523
1234
|
allowNull: true,
|
|
1524
|
-
|
|
1525
1235
|
type: "uuidv4",
|
|
1526
|
-
|
|
1527
1236
|
},
|
|
1528
|
-
|
|
1529
1237
|
batchId: {
|
|
1530
|
-
|
|
1531
1238
|
mandatory: true,
|
|
1532
|
-
|
|
1533
1239
|
allowNull: true,
|
|
1534
|
-
|
|
1535
1240
|
type: "objectId",
|
|
1536
|
-
|
|
1537
1241
|
},
|
|
1538
|
-
|
|
1539
1242
|
firstName: {
|
|
1540
|
-
|
|
1541
1243
|
mandatory: true,
|
|
1542
|
-
|
|
1543
1244
|
type: "string",
|
|
1544
|
-
|
|
1545
1245
|
minLength: 3,
|
|
1546
|
-
|
|
1547
1246
|
},
|
|
1548
|
-
|
|
1549
1247
|
lastName: {
|
|
1550
|
-
|
|
1551
1248
|
mandatory: false,
|
|
1552
|
-
|
|
1553
1249
|
allowNull: true,
|
|
1554
|
-
|
|
1555
1250
|
type: "string",
|
|
1556
|
-
|
|
1557
1251
|
},
|
|
1558
|
-
|
|
1559
1252
|
age: {
|
|
1560
|
-
|
|
1561
1253
|
type: "number",
|
|
1562
|
-
|
|
1563
1254
|
min: 0.1,
|
|
1564
|
-
|
|
1565
1255
|
max: 120,
|
|
1566
|
-
|
|
1567
1256
|
},
|
|
1568
|
-
|
|
1569
1257
|
isAdult: {
|
|
1570
|
-
|
|
1571
1258
|
type: "boolean",
|
|
1572
|
-
|
|
1573
1259
|
},
|
|
1574
|
-
|
|
1575
1260
|
totalWins: {
|
|
1576
|
-
|
|
1577
1261
|
type: "number",
|
|
1578
|
-
|
|
1579
1262
|
min: 0,
|
|
1580
|
-
|
|
1581
1263
|
preventDecimal: true,
|
|
1582
|
-
|
|
1583
1264
|
},
|
|
1584
|
-
|
|
1585
1265
|
email: {
|
|
1586
|
-
|
|
1587
1266
|
regex: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/,
|
|
1588
|
-
|
|
1589
1267
|
},
|
|
1590
|
-
|
|
1591
1268
|
githubLink: {
|
|
1592
|
-
|
|
1593
1269
|
type: "url",
|
|
1594
|
-
|
|
1595
1270
|
},
|
|
1596
|
-
|
|
1597
1271
|
accountStatus: {
|
|
1598
|
-
|
|
1599
1272
|
type: "enum",
|
|
1600
|
-
|
|
1601
1273
|
enumValues: ["Active", "Inactive", 200],
|
|
1602
|
-
|
|
1603
1274
|
},
|
|
1604
|
-
|
|
1605
1275
|
marks: {
|
|
1606
|
-
|
|
1607
1276
|
range: "0-100",
|
|
1608
|
-
|
|
1609
1277
|
},
|
|
1610
|
-
|
|
1611
1278
|
allMarks: {
|
|
1612
|
-
|
|
1613
1279
|
type: "array",
|
|
1614
|
-
|
|
1615
1280
|
allowEmptyArray: false,
|
|
1616
|
-
|
|
1617
1281
|
elementConstraints: {
|
|
1618
|
-
|
|
1619
1282
|
type: "number",
|
|
1620
|
-
|
|
1621
1283
|
allowNull: false,
|
|
1622
|
-
|
|
1623
1284
|
range: "0-100",
|
|
1624
|
-
|
|
1625
1285
|
},
|
|
1626
|
-
|
|
1627
1286
|
},
|
|
1628
|
-
|
|
1629
1287
|
totalScore: {
|
|
1630
|
-
|
|
1631
1288
|
type: "number",
|
|
1632
|
-
|
|
1633
1289
|
dependency: {
|
|
1634
|
-
|
|
1635
1290
|
result: {
|
|
1636
|
-
|
|
1637
1291
|
setDependencyRule: (totalScore, result) => {
|
|
1638
|
-
|
|
1639
1292
|
return { mandatory: true, allowNull: false, type: "string" };
|
|
1640
|
-
|
|
1641
1293
|
},
|
|
1642
|
-
|
|
1643
1294
|
},
|
|
1644
|
-
|
|
1645
1295
|
},
|
|
1646
|
-
|
|
1647
1296
|
},
|
|
1648
|
-
|
|
1649
1297
|
result: {
|
|
1650
|
-
|
|
1651
1298
|
type: "string",
|
|
1652
|
-
|
|
1653
1299
|
dependency: {
|
|
1654
|
-
|
|
1655
1300
|
totalScore: {
|
|
1656
|
-
|
|
1657
1301
|
setDependencyRule: (result, totalScore) => {
|
|
1658
|
-
|
|
1659
1302
|
return { mandatory: true, allowNull: false, type: "number" };
|
|
1660
|
-
|
|
1661
1303
|
},
|
|
1662
|
-
|
|
1663
1304
|
},
|
|
1664
|
-
|
|
1665
1305
|
},
|
|
1666
|
-
|
|
1667
1306
|
},
|
|
1668
|
-
|
|
1669
1307
|
minSalary: {
|
|
1670
|
-
|
|
1671
1308
|
mandatory: true,
|
|
1672
|
-
|
|
1673
1309
|
min: 1,
|
|
1674
|
-
|
|
1675
1310
|
type: "number",
|
|
1676
|
-
|
|
1677
1311
|
dependency: {
|
|
1678
|
-
|
|
1679
1312
|
maxSalary: {
|
|
1680
|
-
|
|
1681
1313
|
setDependencyRule: (minSalary, maxSalary) => {
|
|
1682
|
-
|
|
1683
1314
|
return {
|
|
1684
|
-
|
|
1685
1315
|
mandatory: true,
|
|
1686
|
-
|
|
1687
1316
|
min: minSalary + 1,
|
|
1688
|
-
|
|
1689
1317
|
minError: "maxSalary must be more than minSalary",
|
|
1690
|
-
|
|
1691
1318
|
};
|
|
1692
|
-
|
|
1693
1319
|
},
|
|
1694
|
-
|
|
1695
1320
|
},
|
|
1696
|
-
|
|
1697
1321
|
},
|
|
1698
|
-
|
|
1699
1322
|
},
|
|
1700
|
-
|
|
1701
1323
|
maxSalary: {
|
|
1702
|
-
|
|
1703
1324
|
dependency: {
|
|
1704
|
-
|
|
1705
1325
|
minSalary: {
|
|
1706
|
-
|
|
1707
1326
|
setDependencyRule: (maxSalary, minSalary) => {
|
|
1708
|
-
|
|
1709
1327
|
return {
|
|
1710
|
-
|
|
1711
1328
|
mandatory: true,
|
|
1712
|
-
|
|
1713
1329
|
max: maxSalary - 1,
|
|
1714
|
-
|
|
1715
1330
|
maxError: "minSalary must be less than maxSalary",
|
|
1716
|
-
|
|
1717
1331
|
};
|
|
1718
|
-
|
|
1719
1332
|
},
|
|
1720
|
-
|
|
1721
1333
|
},
|
|
1722
|
-
|
|
1723
1334
|
},
|
|
1724
|
-
|
|
1725
1335
|
},
|
|
1726
|
-
|
|
1727
1336
|
address: {
|
|
1728
|
-
|
|
1729
1337
|
mandatory: true,
|
|
1730
|
-
|
|
1731
1338
|
type: "object",
|
|
1732
|
-
|
|
1733
1339
|
allowEmptyObject: false,
|
|
1734
|
-
|
|
1735
1340
|
objectAttr: {
|
|
1736
|
-
|
|
1737
1341
|
country: { mandatory: true, type: "string" },
|
|
1738
|
-
|
|
1739
1342
|
state: {
|
|
1740
|
-
|
|
1741
1343
|
mandatory: true,
|
|
1742
|
-
|
|
1743
1344
|
type: "string",
|
|
1744
|
-
|
|
1745
1345
|
},
|
|
1746
|
-
|
|
1747
1346
|
city: {},
|
|
1748
|
-
|
|
1749
1347
|
zip: {
|
|
1750
|
-
|
|
1751
1348
|
mandatory: true,
|
|
1752
|
-
|
|
1753
1349
|
type: "string",
|
|
1754
|
-
|
|
1755
1350
|
},
|
|
1756
|
-
|
|
1757
1351
|
position: {
|
|
1758
|
-
|
|
1759
1352
|
mandatory: true,
|
|
1760
|
-
|
|
1761
1353
|
type: "object",
|
|
1762
|
-
|
|
1763
1354
|
allowEmptyObject: false,
|
|
1764
|
-
|
|
1765
1355
|
objectAttr: {
|
|
1766
|
-
|
|
1767
1356
|
lattitude: { mandatory: true, type: "number" },
|
|
1768
|
-
|
|
1769
1357
|
longitude: {
|
|
1770
|
-
|
|
1771
1358
|
mandatory: true,
|
|
1772
|
-
|
|
1773
1359
|
type: "number",
|
|
1774
|
-
|
|
1775
1360
|
},
|
|
1776
|
-
|
|
1777
1361
|
},
|
|
1778
|
-
|
|
1779
1362
|
},
|
|
1780
|
-
|
|
1781
1363
|
},
|
|
1782
|
-
|
|
1783
1364
|
},
|
|
1784
|
-
|
|
1785
1365
|
}
|
|
1786
1366
|
```
|
|
1787
1367
|
|
|
@@ -1794,13 +1374,9 @@ sample-2
|
|
|
1794
1374
|
//Here validatePayload is your middleware function, where you're invoking perfect payload
|
|
1795
1375
|
|
|
1796
1376
|
router.post(
|
|
1797
|
-
|
|
1798
1377
|
"/payload-validation",
|
|
1799
|
-
|
|
1800
1378
|
validatePayload({ rule: <your validation rule json object> }),
|
|
1801
|
-
|
|
1802
1379
|
(req, res) => res.send("OK")
|
|
1803
|
-
|
|
1804
1380
|
);
|
|
1805
1381
|
```
|
|
1806
1382
|
|
|
@@ -1813,15 +1389,12 @@ export const validatePayload = ({ rule }) => {
|
|
|
1813
1389
|
return (req, res, next) => {
|
|
1814
1390
|
try {
|
|
1815
1391
|
const { statusCode, ...response } = perfectPayloadV1(req?.body, rule);
|
|
1816
|
-
|
|
1817
1392
|
if (+statusCode >= 200 && +statusCode <= 299) {
|
|
1818
1393
|
req.validatedBody = response?.validatedPayload;
|
|
1819
|
-
|
|
1820
1394
|
next();
|
|
1821
1395
|
} else res.status(statusCode).json(response);
|
|
1822
1396
|
} catch (error) {
|
|
1823
1397
|
console.error("Error validating payload", error);
|
|
1824
|
-
|
|
1825
1398
|
res.status(500).json({ error: "Internal Server Error" });
|
|
1826
1399
|
}
|
|
1827
1400
|
};
|
|
@@ -1835,19 +1408,15 @@ function validatePayload({ rule }) {
|
|
|
1835
1408
|
return async (req, res, next) => {
|
|
1836
1409
|
try {
|
|
1837
1410
|
const { perfectPayloadV1 } = await import("perfect-payload");
|
|
1838
|
-
|
|
1839
1411
|
const { statusCode, ...response } = perfectPayloadV1(req?.body, rule);
|
|
1840
|
-
|
|
1841
1412
|
if (+statusCode >= 200 && +statusCode <= 299) {
|
|
1842
1413
|
req.validatedBody = response?.validatedPayload;
|
|
1843
|
-
|
|
1844
1414
|
next();
|
|
1845
1415
|
} else {
|
|
1846
1416
|
res.status(statusCode).json(response);
|
|
1847
1417
|
}
|
|
1848
1418
|
} catch (error) {
|
|
1849
1419
|
console.error("Error validating payload", error);
|
|
1850
|
-
|
|
1851
1420
|
res.status(500).json({ error: "Internal Server Error" });
|
|
1852
1421
|
}
|
|
1853
1422
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "perfect-payload",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Lightweight JSON payload validation library with structured errors, nested validation, field paths, and customizable validation rules.",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "jest"
|
|
@@ -12,14 +12,22 @@
|
|
|
12
12
|
"url": "git+https://github.com/kiranpoojary/perfect-payload.git"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
15
|
-
"validation",
|
|
15
|
+
"payload-validation",
|
|
16
|
+
"request-validation",
|
|
17
|
+
"nodejs-validation",
|
|
18
|
+
"javascript-validation",
|
|
19
|
+
"api-validation",
|
|
20
|
+
"object-validation",
|
|
21
|
+
"json-validation",
|
|
22
|
+
"schema-validation",
|
|
23
|
+
"express-validation",
|
|
24
|
+
"fastify-validation",
|
|
25
|
+
"validator",
|
|
16
26
|
"payload",
|
|
17
27
|
"api",
|
|
18
28
|
"data",
|
|
19
29
|
"request-body",
|
|
20
|
-
"
|
|
21
|
-
"express",
|
|
22
|
-
"validate"
|
|
30
|
+
"express"
|
|
23
31
|
],
|
|
24
32
|
"author": "Kiran Poojary",
|
|
25
33
|
"license": "ISC",
|