perfect-payload 1.3.0-beta.2 → 1.5.0-beta.0

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.
Files changed (3) hide show
  1. package/README.md +767 -376
  2. package/index.js +148 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,15 +1,34 @@
1
1
  # perfect-payload
2
2
 
3
3
  A lightweight JavaScript payload validation utility for validating API
4
-
5
4
  and JSON payloads with simple rule-based configuration.
6
5
 
6
+ `perfect-payload` supports structured validation errors, nested field
7
+ paths, synchronous custom validators, synchronous payload
8
+ transformation/sanitization, array size constraints, and deeply nested
9
+ array/object validation while keeping the validation schema simple.
10
+
11
+ ## Quick Links
12
+
13
+ - [Installation](#installation)
14
+ - [Basic Usage](#basic-usage)
15
+ - [Validation Rules](#validation-rules)
16
+ - [Array Size and Nested Validation](#array-size-and-nested-validation)
17
+ - [Transformations and
18
+ Sanitization](#transformations-and-sanitization)
19
+ - [Custom Validators](#customvalidator)
20
+ - [Error Codes](#error-codes)
21
+ - [Custom Error Messages](#custom-error-messages)
22
+ - [Nested Objects and Array Field
23
+ Paths](#nested-objects-and-array-field-paths)
24
+ - [Examples and Usage](#examples-and-usage)
25
+ - [Legacy API](#legacy-api)
26
+
7
27
  ## Installation
8
28
 
9
29
  ```bash
10
30
 
11
31
  npm install perfect-payload
12
-
13
32
  ```
14
33
 
15
34
  ## Basic Usage
@@ -60,25 +79,25 @@ console.log(result);
60
79
 
61
80
  {
62
81
 
63
- statusCode: 200,
82
+   statusCode: 200,
64
83
 
65
- valid: true,
84
+   valid: true,
66
85
 
67
- validatedPayload: {
86
+   validatedPayload: {
68
87
 
69
- name: "Kiran",
88
+     name: "Kiran",
70
89
 
71
- email: "kiran@example.com",
90
+     email: "kiran@example.com",
72
91
 
73
- age: 29
92
+     age: 29
74
93
 
75
- }
94
+   }
76
95
 
77
96
  }
78
-
79
97
  ```
80
98
 
81
- **Note:** The validatedPayload contains only the fields defined in the
99
+ Note: The validatedPayload contains only the fields
100
+ defined in the
82
101
 
83
102
  schema, automatically filtering out any extra attributes. You can use it
84
103
 
@@ -92,28 +111,27 @@ to safely overwrite request.body or assign it to a new request property
92
111
 
93
112
  {
94
113
 
95
- statusCode: 400,
114
+   statusCode: 400,
96
115
 
97
- valid: false,
116
+   valid: false,
98
117
 
99
- message: "One or more attribute values are invalid",
118
+   message: "One or more attribute values are invalid",
100
119
 
101
- errors: [
120
+   errors: [
102
121
 
103
- {
122
+     {
104
123
 
105
- path: "email",
124
+       path: "email",
106
125
 
107
- code: "INVALID_EMAIL",
126
+       code: "INVALID_EMAIL",
108
127
 
109
- message: "Invalid email format for attribute email"
128
+       message: "Invalid email format for attribute email"
110
129
 
111
- }
130
+     }
112
131
 
113
- ]
132
+   ]
114
133
 
115
134
  }
116
-
117
135
  ```
118
136
 
119
137
  Each error returned by `perfectPayload()` contains:
@@ -122,14 +140,13 @@ Each error returned by `perfectPayload()` contains:
122
140
 
123
141
  {
124
142
 
125
- path: "field.path",
143
+   path: "field.path",
126
144
 
127
- code: "ERROR_CODE",
145
+   code: "ERROR_CODE",
128
146
 
129
- message: "Human readable validation message"
147
+   message: "Human readable validation message"
130
148
 
131
149
  }
132
-
133
150
  ```
134
151
 
135
152
  \- `path` identifies the exact field that failed validation.
@@ -152,7 +169,7 @@ import { perfectPayloadV1 } from "perfect-payload";
152
169
 
153
170
  `perfectPayloadV1()` is deprecated and will no longer be supported after
154
171
 
155
- **March 31, 2027**.
172
+ March 31, 2027.
156
173
 
157
174
  Existing applications can continue using it during the migration period,
158
175
 
@@ -182,7 +199,8 @@ errors: [
182
199
  ];
183
200
  ```
184
201
 
185
- **Note:** If an inValidPayloadResponse is provided, the system returns
202
+ Note: If an inValidPayloadResponse is provided, the
203
+ system returns
186
204
 
187
205
  it alongside an automatically generated errors property. Do not include
188
206
 
@@ -192,13 +210,14 @@ object.
192
210
 
193
211
  ## Validation Rules
194
212
 
195
- `perfectPayload()` supports the following validation rules.
213
+ `perfectPayload()` supports validation, nested-schema,
214
+ custom-validation, and transformation rules.
196
215
 
197
216
  ### `mandatory`
198
217
 
199
- Marks a field as required(even empty string also not allowed)
218
+ Marks a field as required. An empty string is also treated as missing.
200
219
 
201
- **Default:** `false`, the field is not required.
220
+ Default: `false`, the field is not required.
202
221
 
203
222
  ```js
204
223
  const rules = {
@@ -210,13 +229,13 @@ const rules = {
210
229
 
211
230
  Error code: `REQUIRED`
212
231
 
213
- **---**
232
+ ---
214
233
 
215
234
  ### `allowNull`
216
235
 
217
236
  Controls whether `null` values are accepted.
218
237
 
219
- **Default:** `true` , `null` values are allowed.
238
+ Default: `true`, `null` values are allowed.
220
239
 
221
240
  Example:
222
241
 
@@ -230,13 +249,13 @@ const rules = {
230
249
 
231
250
  Error code: `NULL_NOT_ALLOWED`
232
251
 
233
- **---**
252
+ ---
234
253
 
235
254
  ### `allowEmptyObject`
236
255
 
237
256
  Controls whether an empty object `{}` is accepted.
238
257
 
239
- **Default:** `true`, empty objects are allowed.
258
+ Default: `true`, empty objects are allowed.
240
259
 
241
260
  Example:
242
261
 
@@ -252,13 +271,13 @@ const rules = {
252
271
 
253
272
  Error code: `EMPTY_OBJECT_NOT_ALLOWED`
254
273
 
255
- **---**
274
+ ---
256
275
 
257
276
  ### `allowEmptyArray`
258
277
 
259
278
  Controls whether an empty array `[]` is accepted.
260
279
 
261
- **Default:** `true`, empty arrays are allowed.
280
+ Default: `true`, empty arrays are allowed.
262
281
 
263
282
  Example:
264
283
 
@@ -274,7 +293,69 @@ const rules = {
274
293
 
275
294
  Error code: `EMPTY_ARRAY_NOT_ALLOWED`
276
295
 
277
- **---**
296
+ ---
297
+
298
+ ### `minItems`
299
+
300
+ Defines the minimum number of items required in an array.
301
+
302
+ Default: Not applied when omitted.
303
+
304
+ ```js
305
+ const rules = {
306
+ tags: {
307
+ type: "array",
308
+ minItems: 2,
309
+ },
310
+ };
311
+ ```
312
+
313
+ An array with fewer than 2 items returns `MIN_ITEMS`.
314
+
315
+ ```js
316
+ {
317
+ path: "tags",
318
+ code: "MIN_ITEMS",
319
+ message: "Attribute tags must contain at least 2 item(s)"
320
+ }
321
+ ```
322
+
323
+ `minItems` is enforced even when `allowEmptyArray: true` is set. For example, `minItems: 2` still rejects `[]`.
324
+
325
+ Error code: `MIN_ITEMS`
326
+
327
+ ---
328
+
329
+ ### `maxItems`
330
+
331
+ Defines the maximum number of items allowed in an array.
332
+
333
+ Default: Not applied when omitted.
334
+
335
+ ```js
336
+ const rules = {
337
+ tags: {
338
+ type: "array",
339
+ maxItems: 5,
340
+ },
341
+ };
342
+ ```
343
+
344
+ An array with more than 5 items returns `MAX_ITEMS`.
345
+
346
+ ```js
347
+ {
348
+ path: "tags",
349
+ code: "MAX_ITEMS",
350
+ message: "Attribute tags must contain at most 5 item(s)"
351
+ }
352
+ ```
353
+
354
+ `minItems` and `maxItems` can be used together.
355
+
356
+ Error code: `MAX_ITEMS`
357
+
358
+ ---
278
359
 
279
360
  ### `type`
280
361
 
@@ -311,7 +392,6 @@ objectId
311
392
  array
312
393
 
313
394
  object
314
-
315
395
  ```
316
396
 
317
397
  Example:
@@ -397,16 +477,17 @@ INVALID_UUID_V4
397
477
  INVALID_UUID_V5
398
478
 
399
479
  INVALID_OBJECT_ID
400
-
401
480
  ```
402
481
 
403
- **---**
482
+ For `type: "number"`, `NaN` is rejected as `INVALID_TYPE`.
483
+
484
+ ---
404
485
 
405
486
  ### `regex`
406
487
 
407
488
  Validates a value using a regular expression.
408
489
 
409
- **Default:** Not applied when omitted.
490
+ Default: Not applied when omitted.
410
491
 
411
492
  Example:
412
493
 
@@ -422,13 +503,13 @@ const rules = {
422
503
 
423
504
  Error code: `REGEX_MISMATCH`
424
505
 
425
- **---**
506
+ ---
426
507
 
427
508
  ### `minLength`
428
509
 
429
510
  Defines the minimum allowed string length.
430
511
 
431
- **Default:** Not applied when omitted.
512
+ Default: Not applied when omitted.
432
513
 
433
514
  Example:
434
515
 
@@ -444,13 +525,13 @@ const rules = {
444
525
 
445
526
  Error code: `MIN_LENGTH`
446
527
 
447
- **---**
528
+ ---
448
529
 
449
530
  ### `maxLength`
450
531
 
451
532
  Defines the maximum allowed string length.
452
533
 
453
- **Default:** Not applied when omitted.
534
+ Default: Not applied when omitted.
454
535
 
455
536
  Example:
456
537
 
@@ -466,13 +547,14 @@ const rules = {
466
547
 
467
548
  Error code: `MAX_LENGTH`
468
549
 
469
- **---**
550
+ ---
470
551
 
471
552
  ### `preventDecimal`
472
553
 
473
554
  Prevents decimal numbers.
474
555
 
475
- **Default:** `false` both integer and decimal numbers are allowed.
556
+ Default: `false`; both integer and decimal numbers are
557
+ allowed.
476
558
 
477
559
  Example:
478
560
 
@@ -488,13 +570,13 @@ const rules = {
488
570
 
489
571
  Error code: `DECIMAL_NOT_ALLOWED`
490
572
 
491
- **---**
573
+ ---
492
574
 
493
575
  ### `min`
494
576
 
495
577
  Defines the minimum allowed numeric value.
496
578
 
497
- **Default:** Not applied when omitted.
579
+ Default: Not applied when omitted.
498
580
 
499
581
  Example:
500
582
 
@@ -510,13 +592,13 @@ const rules = {
510
592
 
511
593
  Error code: `MIN_VALUE`
512
594
 
513
- **---**
595
+ ---
514
596
 
515
597
  ### `max`
516
598
 
517
599
  Defines the maximum allowed numeric value.
518
600
 
519
- **Default:** Not applied when omitted.
601
+ Default: Not applied when omitted.
520
602
 
521
603
  Example:
522
604
 
@@ -532,13 +614,13 @@ const rules = {
532
614
 
533
615
  Error code: `MAX_VALUE`
534
616
 
535
- **---**
617
+ ---
536
618
 
537
619
  ### `range`
538
620
 
539
621
  Defines the allowed numeric range.
540
622
 
541
- **Default:** Not applied when omitted.
623
+ Default: Not applied when omitted.
542
624
 
543
625
  Example:
544
626
 
@@ -554,7 +636,7 @@ const rules = {
554
636
 
555
637
  Error code: `OUT_OF_RANGE`
556
638
 
557
- **---**
639
+ ---
558
640
 
559
641
  ### `elementConstraints`
560
642
 
@@ -582,16 +664,15 @@ Example error:
582
664
 
583
665
  {
584
666
 
585
- path: "marks[2]",
667
+   path: "marks[2]",
586
668
 
587
- code: "OUT_OF_RANGE",
669
+   code: "OUT_OF_RANGE",
588
670
 
589
- message:
671
+   message:
590
672
 
591
- "Attribute marks[2] should have a value between 0 and 100"
673
+     "Attribute marks[2] should have a value between 0 and 100"
592
674
 
593
675
  }
594
-
595
676
  ```
596
677
 
597
678
  When `elementConstraintsError` is explicitly provided, the error code
@@ -614,7 +695,7 @@ const rules = {
614
695
  };
615
696
  ```
616
697
 
617
- **---**
698
+ ---
618
699
 
619
700
  ### `objectAttr`
620
701
 
@@ -658,19 +739,18 @@ Nested errors include the complete field path:
658
739
 
659
740
  {
660
741
 
661
- path: "address.location.latitude",
742
+   path: "address.location.latitude",
662
743
 
663
- code: "INVALID_TYPE",
744
+   code: "INVALID_TYPE",
664
745
 
665
- message:
746
+   message:
666
747
 
667
- "Invalid type for attribute address.location.latitude, required number value"
748
+     "Invalid type for attribute address.location.latitude, required number value"
668
749
 
669
750
  }
670
-
671
751
  ```
672
752
 
673
- **---**
753
+ ---
674
754
 
675
755
  ### `dependency`
676
756
 
@@ -704,25 +784,326 @@ Example error:
704
784
 
705
785
  {
706
786
 
707
- path: "maxSalary",
787
+   path: "maxSalary",
788
+
789
+   code: "MIN_VALUE",
790
+
791
+   message:
792
+
793
+     "maxSalary must be more than minSalary"
794
+
795
+ }
796
+ ```
797
+
798
+ ---
799
+
800
+ ## Array Size and Nested Validation
801
+
802
+ `perfectPayload()` supports array size constraints and recursive validation of arrays and objects at multiple depths. Array indexes and nested object keys are preserved in structured error paths.
708
803
 
709
- code: "MIN_VALUE",
804
+ ### Array size constraints
710
805
 
711
- message:
806
+ Use `minItems` and `maxItems` with `type: "array"`:
712
807
 
713
- "maxSalary must be more than minSalary"
808
+ ```js
809
+ const rules = {
810
+ products: {
811
+ type: "array",
812
+ minItems: 1,
813
+ maxItems: 3,
814
+ elementConstraints: {
815
+ type: "object",
816
+ objectAttr: {
817
+ productId: { mandatory: true, type: "string" },
818
+ quantity: { mandatory: true, type: "number", min: 1 },
819
+ },
820
+ },
821
+ },
822
+ };
823
+ ```
824
+
825
+ If the array is empty, `minItems` reports the array path itself:
714
826
 
827
+ ```js
828
+ {
829
+ path: "products",
830
+ code: "MIN_ITEMS",
831
+ message: "Attribute products must contain at least 1 item(s)"
715
832
  }
833
+ ```
834
+
835
+ ### Arrays of objects
836
+
837
+ `elementConstraints` can contain `objectAttr`, allowing every object in an array to use a nested schema. An invalid quantity in the second product is reported as:
838
+
839
+ ```text
840
+ products[1].quantity
841
+ ```
842
+
843
+ ### Deeply nested arrays and objects
844
+
845
+ `objectAttr` and `elementConstraints` can be combined recursively:
846
+
847
+ ```js
848
+ const rules = {
849
+ orders: {
850
+ type: "array",
851
+ minItems: 1,
852
+ maxItems: 2,
853
+ elementConstraints: {
854
+ type: "object",
855
+ objectAttr: {
856
+ orderId: { mandatory: true, type: "string" },
857
+ items: {
858
+ mandatory: true,
859
+ type: "array",
860
+ minItems: 1,
861
+ maxItems: 2,
862
+ elementConstraints: {
863
+ type: "object",
864
+ objectAttr: {
865
+ productId: { mandatory: true, type: "string" },
866
+ quantity: { mandatory: true, type: "number", min: 1 },
867
+ },
868
+ },
869
+ },
870
+ },
871
+ },
872
+ },
873
+ };
874
+ ```
875
+
876
+ A deep validation failure preserves the complete indexed path, for example:
877
+
878
+ ```text
879
+ orders[1].items[2].quantity
880
+ ```
716
881
 
882
+ Array constraints work at nested levels too. A nested array can report paths such as:
883
+
884
+ ```text
885
+ orders[1].items
717
886
  ```
718
887
 
719
- **---**
888
+ Nested arrays are supported and every array index is preserved:
889
+
890
+ ```text
891
+ matrix[1][1]
892
+ matrix[1][1][1]
893
+ ```
894
+
895
+ Transformations applied inside nested objects or array elements are preserved in `validatedPayload`, while the original input remains unchanged.
896
+
897
+ ### Transformations and Sanitization
898
+
899
+ `perfectPayload()` can transform a field before its validation rules
900
+ run. The transformed value is returned in `validatedPayload`, while the
901
+ original input object is not mutated.
902
+
903
+ Supported transformation rules:
904
+
905
+ Rule Purpose
906
+
907
+ ---
908
+
909
+ `trim` Removes leading and trailing whitespace from strings
910
+ `lowercase` Converts strings to lowercase
911
+ `uppercase` Converts strings to uppercase
912
+ `transform` Runs a custom synchronous transformation function
913
+
914
+ Transformations always run in this fixed order, regardless of the order
915
+ in which the rule properties are written:
916
+
917
+ ```text
918
+ trim
919
+
920
+ lowercase
921
+
922
+ uppercase
923
+
924
+ transform(value, payload)
925
+
926
+ validation rules
927
+
928
+ customValidator
929
+
930
+ validatedPayload
931
+ ```
932
+
933
+ #### `trim`
934
+
935
+ ```js
936
+ const payload = {
937
+ name: " Kiran Poojary ",
938
+ };
939
+
940
+ const rules = {
941
+ name: {
942
+ type: "string",
943
+ trim: true,
944
+ },
945
+ };
946
+
947
+ const result = perfectPayload(payload, rules);
948
+
949
+ console.log(result.validatedPayload.name);
950
+ // "Kiran Poojary"
951
+
952
+ console.log(payload.name);
953
+ // " Kiran Poojary "
954
+ ```
955
+
956
+ `trim` applies only to string values. Non-string values are left
957
+ unchanged.
958
+
959
+ #### `lowercase`
960
+
961
+ ```js
962
+ const rules = {
963
+ email: {
964
+ trim: true,
965
+ lowercase: true,
966
+ type: "email",
967
+ },
968
+ };
969
+ ```
970
+
971
+ For `" KIRAN@EXAMPLE.COM "`, the validated value becomes
972
+ `"kiran@example.com"`.
973
+
974
+ #### `uppercase`
975
+
976
+ ```js
977
+ const rules = {
978
+ countryCode: {
979
+ type: "string",
980
+ uppercase: true,
981
+ },
982
+ };
983
+ ```
984
+
985
+ For `"in"`, the validated value becomes `"IN"`.
986
+
987
+ `lowercase: true` and `uppercase: true` cannot be enabled together for
988
+ the same field. Doing so throws a schema configuration error.
989
+
990
+ #### `transform`
991
+
992
+ Use `transform` when the built-in string transformations are not enough.
993
+
994
+ ```js
995
+ const rules = {
996
+ phone: {
997
+ type: "string",
998
+ transform: (value) => value.replace(/\s+/g, ""),
999
+ },
1000
+ };
1001
+ ```
1002
+
1003
+ For `"98765 43210"`, the validated value becomes `"9876543210"`.
1004
+
1005
+ The transformer receives two arguments:
1006
+
1007
+ ```js
1008
+ transform: (value, payload) => {
1009
+ return value;
1010
+ };
1011
+ ```
1012
+
1013
+ - `value` is the field value after the built-in transformations have
1014
+ run.
1015
+ - `payload` is the current payload/object being validated.
1016
+
1017
+ This makes cross-field transformations possible:
1018
+
1019
+ ```js
1020
+ const payload = {
1021
+ amount: 100,
1022
+ multiplier: 2,
1023
+ };
1024
+
1025
+ const rules = {
1026
+ amount: {
1027
+ transform: (value, payload) => value * payload.multiplier,
1028
+ type: "number",
1029
+ },
1030
+ multiplier: {
1031
+ type: "number",
1032
+ },
1033
+ };
1034
+
1035
+ const result = perfectPayload(payload, rules);
1036
+
1037
+ console.log(result.validatedPayload.amount);
1038
+ // 200
1039
+ ```
1040
+
1041
+ A custom transformer may also change the data type before validation:
1042
+
1043
+ ```js
1044
+ const rules = {
1045
+ quantity: {
1046
+ transform: (value) => Number(value),
1047
+ type: "number",
1048
+ min: 1,
1049
+ max: 100,
1050
+ },
1051
+ };
1052
+ ```
1053
+
1054
+ The transformed value is validated by the normal validation rules and is
1055
+ also the value received by `customValidator`.
1056
+
1057
+ Transformations work inside `objectAttr` and `elementConstraints`, and
1058
+ transformed nested/array values are preserved in `validatedPayload`.
1059
+
1060
+ ```js
1061
+ const rules = {
1062
+ profile: {
1063
+ type: "object",
1064
+ objectAttr: {
1065
+ name: {
1066
+ trim: true,
1067
+ uppercase: true,
1068
+ type: "string",
1069
+ },
1070
+ },
1071
+ },
1072
+ tags: {
1073
+ type: "array",
1074
+ elementConstraints: {
1075
+ trim: true,
1076
+ lowercase: true,
1077
+ type: "string",
1078
+ },
1079
+ },
1080
+ };
1081
+ ```
1082
+
1083
+ Missing optional fields are not transformed. An input value of `null` is
1084
+ not passed to transformation functions; null handling remains controlled
1085
+ by `allowNull`.
1086
+
1087
+ **Important:** `transform` is synchronous. A non-function transformer,
1088
+ an `async` transformer, a transformer that returns a Promise, or a
1089
+ transformer that returns `undefined` is not supported and throws an error.
1090
+ Returning `null`, `""`, `0`, or `false` is allowed; the transformed value is
1091
+ then processed by the normal validation rules. Exceptions thrown inside the
1092
+ transformer propagate to the caller.
1093
+
1094
+ For example, returning `undefined` throws:
1095
+
1096
+ ```text
1097
+ perfect-payload:- transform must not return undefined for attribute username
1098
+ ```
720
1099
 
721
1100
  ### `customValidator`
722
1101
 
723
- Allows you to define custom synchronous validation logic for a field when the built-in validation rules are not enough.
1102
+ Allows you to define custom synchronous validation logic for a field
1103
+ when the built-in validation rules are not enough.
724
1104
 
725
- The validator receives the field value and the complete payload:
1105
+ The validator receives the field value and the current payload/object
1106
+ being validated:
726
1107
 
727
1108
  ```js
728
1109
  customValidator: (value, payload) => {
@@ -730,7 +1111,8 @@ customValidator: (value, payload) => {
730
1111
  };
731
1112
  ```
732
1113
 
733
- The validator must return `true` to pass validation. Any other return value causes validation to fail.
1114
+ The validator must return `true` to pass validation. Any other return
1115
+ value causes validation to fail.
734
1116
 
735
1117
  Example:
736
1118
 
@@ -738,11 +1120,15 @@ Example:
738
1120
  const rules = {
739
1121
  username: {
740
1122
  mandatory: true,
1123
+
741
1124
  type: "string",
1125
+
742
1126
  customValidator: (value) => {
743
1127
  return !value.toLowerCase().includes("admin");
744
1128
  },
1129
+
745
1130
  customValidatorCode: "RESERVED_USERNAME",
1131
+
746
1132
  customValidatorError: "Username cannot contain admin",
747
1133
  },
748
1134
  };
@@ -759,44 +1145,64 @@ const payload = {
759
1145
  The validation error is:
760
1146
 
761
1147
  ```js
1148
+
762
1149
  {
763
- path: "username",
764
- code: "RESERVED_USERNAME",
765
- message: "Username cannot contain admin"
1150
+
1151
+   path: "username",
1152
+
1153
+   code: "RESERVED_USERNAME",
1154
+
1155
+   message: "Username cannot contain admin"
1156
+
766
1157
  }
767
1158
  ```
768
1159
 
769
- If `customValidatorCode` and `customValidatorError` are not provided, the default error is:
1160
+ If `customValidatorCode` and `customValidatorError` are not provided,
1161
+ the default error is:
770
1162
 
771
1163
  ```js
1164
+
772
1165
  {
773
- path: "username",
774
- code: "CUSTOM_VALIDATION_FAILED",
775
- message: "Custom validation failed for attribute username"
1166
+
1167
+   path: "username",
1168
+
1169
+   code: "CUSTOM_VALIDATION_FAILED",
1170
+
1171
+   message: "Custom validation failed for attribute username"
1172
+
776
1173
  }
777
1174
  ```
778
1175
 
779
- The complete payload can be used as the second argument when required:
1176
+ The current payload/object being validated can be used as the second
1177
+ argument when required:
780
1178
 
781
1179
  ```js
782
1180
  const rules = {
783
1181
  limit: {
784
1182
  type: "number",
785
1183
  },
1184
+
786
1185
  amount: {
787
1186
  type: "number",
1187
+
788
1188
  customValidator: (value, payload) => {
789
1189
  return value <= payload.limit;
790
1190
  },
1191
+
791
1192
  customValidatorCode: "LIMIT_EXCEEDED",
1193
+
792
1194
  customValidatorError: "Amount cannot exceed limit",
793
1195
  },
794
1196
  };
795
1197
  ```
796
1198
 
797
- `customValidator` also works with nested objects and array `elementConstraints`. The generated structured error automatically contains the corresponding nested or array path.
1199
+ `customValidator` also works with nested objects and array
1200
+ `elementConstraints`. The generated structured error automatically
1201
+ contains the corresponding nested or array path.
798
1202
 
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.
1203
+ Important: `customValidator` is synchronous. An `async`
1204
+ validator or a validator that returns a Promise is not supported and
1205
+ throws an error. Asynchronous validation is not part of this feature.
800
1206
 
801
1207
  Error code when no custom code is provided: `CUSTOM_VALIDATION_FAILED`
802
1208
 
@@ -816,6 +1222,10 @@ EMPTY_OBJECT_NOT_ALLOWED
816
1222
 
817
1223
  EMPTY_ARRAY_NOT_ALLOWED
818
1224
 
1225
+ MIN_ITEMS
1226
+
1227
+ MAX_ITEMS
1228
+
819
1229
  INVALID_ARRAY_ELEMENT
820
1230
 
821
1231
  REGEX_MISMATCH
@@ -852,6 +1262,7 @@ MAX_VALUE
852
1262
 
853
1263
  OUT_OF_RANGE
854
1264
 
1265
+ CUSTOM_VALIDATION_FAILED
855
1266
  ```
856
1267
 
857
1268
  These codes are designed for programmatic handling while `message`
@@ -866,20 +1277,19 @@ const result = perfectPayload(payload, validationRules);
866
1277
 
867
1278
  if (!result.valid) {
868
1279
 
869
- const emailError = result.errors.find(
1280
+   const emailError = result.errors.find(
870
1281
 
871
- (error) => error.code === "INVALID_EMAIL",
1282
+     (error) => error.code === "INVALID_EMAIL",
872
1283
 
873
- );
1284
+   );
874
1285
 
875
- if (emailError) {
1286
+   if (emailError) {
876
1287
 
877
- *// Handle invalid email*
1288
+     **// Handle invalid email**
878
1289
 
879
- }
1290
+   }
880
1291
 
881
1292
  }
882
-
883
1293
  ```
884
1294
 
885
1295
  ## Custom Error Messages
@@ -894,14 +1304,13 @@ keeping the same structured error format:
894
1304
 
895
1305
  {
896
1306
 
897
- path: "email",
1307
+   path: "email",
898
1308
 
899
- code: "INVALID_EMAIL",
1309
+   code: "INVALID_EMAIL",
900
1310
 
901
- message: "Email address is invalid"
1311
+   message: "Email address is invalid"
902
1312
 
903
1313
  }
904
-
905
1314
  ```
906
1315
 
907
1316
  Example:
@@ -926,14 +1335,13 @@ If `email` is missing:
926
1335
 
927
1336
  {
928
1337
 
929
- path: "email",
1338
+   path: "email",
930
1339
 
931
- code: "REQUIRED",
1340
+   code: "REQUIRED",
932
1341
 
933
- message: "Email is required"
1342
+   message: "Email is required"
934
1343
 
935
1344
  }
936
-
937
1345
  ```
938
1346
 
939
1347
  If `email` is present but invalid:
@@ -942,14 +1350,13 @@ If `email` is present but invalid:
942
1350
 
943
1351
  {
944
1352
 
945
- path: "email",
1353
+   path: "email",
946
1354
 
947
- code: "INVALID_EMAIL",
1355
+   code: "INVALID_EMAIL",
948
1356
 
949
- message: "Email address is invalid"
1357
+   message: "Email address is invalid"
950
1358
 
951
1359
  }
952
-
953
1360
  ```
954
1361
 
955
1362
  ### Supported Custom Error Properties
@@ -1036,56 +1443,55 @@ Example result:
1036
1443
 
1037
1444
  {
1038
1445
 
1039
- statusCode: 400,
1446
+   statusCode: 400,
1040
1447
 
1041
- valid: false,
1448
+   valid: false,
1042
1449
 
1043
- message:
1450
+   message:
1044
1451
 
1045
- "One or more attribute values are invalid",
1452
+     "One or more attribute values are invalid",
1046
1453
 
1047
- errors: [
1454
+   errors: [
1048
1455
 
1049
- {
1456
+     {
1050
1457
 
1051
- path: "username",
1458
+       path: "username",
1052
1459
 
1053
- code: "MIN_LENGTH",
1460
+       code: "MIN_LENGTH",
1054
1461
 
1055
- message:
1462
+       message:
1056
1463
 
1057
- "Username must contain at least 3 characters"
1464
+         "Username must contain at least 3 characters"
1058
1465
 
1059
- },
1466
+     },
1060
1467
 
1061
- {
1468
+     {
1062
1469
 
1063
- path: "age",
1470
+       path: "age",
1064
1471
 
1065
- code: "MIN_VALUE",
1472
+       code: "MIN_VALUE",
1066
1473
 
1067
- message:
1474
+       message:
1068
1475
 
1069
- "Age must be at least 18"
1476
+         "Age must be at least 18"
1070
1477
 
1071
- },
1478
+     },
1072
1479
 
1073
- {
1480
+     {
1074
1481
 
1075
- path: "score",
1482
+       path: "score",
1076
1483
 
1077
- code: "OUT_OF_RANGE",
1484
+       code: "OUT_OF_RANGE",
1078
1485
 
1079
- message:
1486
+       message:
1080
1487
 
1081
- "Score must be between 0 and 100"
1488
+         "Score must be between 0 and 100"
1082
1489
 
1083
- }
1490
+     }
1084
1491
 
1085
- ]
1492
+   ]
1086
1493
 
1087
1494
  }
1088
-
1089
1495
  ```
1090
1496
 
1091
1497
  ### Custom Messages and Error Codes
@@ -1114,14 +1520,13 @@ Still returns:
1114
1520
 
1115
1521
  {
1116
1522
 
1117
- path: "age",
1523
+   path: "age",
1118
1524
 
1119
- code: "MIN_VALUE",
1525
+   code: "MIN_VALUE",
1120
1526
 
1121
- message: "You must be 18 or older"
1527
+   message: "You must be 18 or older"
1122
1528
 
1123
1529
  }
1124
-
1125
1530
  ```
1126
1531
 
1127
1532
  This makes it possible to:
@@ -1166,24 +1571,23 @@ When validation succeeds, `validatedPayload` is automatically added:
1166
1571
 
1167
1572
  {
1168
1573
 
1169
- statusCode: 201,
1574
+   statusCode: 201,
1170
1575
 
1171
- valid: true,
1576
+   valid: true,
1172
1577
 
1173
- message: "Payload validated successfully",
1578
+   message: "Payload validated successfully",
1174
1579
 
1175
- validatedPayload: {
1580
+   validatedPayload: {
1176
1581
 
1177
- name: "Kiran",
1582
+     name: "Kiran",
1178
1583
 
1179
- email: "kiran@example.com",
1584
+     email: "kiran@example.com",
1180
1585
 
1181
- age: 29
1586
+     age: 29
1182
1587
 
1183
- }
1588
+   }
1184
1589
 
1185
1590
  }
1186
-
1187
1591
  ```
1188
1592
 
1189
1593
  ### Custom Invalid Response
@@ -1216,30 +1620,29 @@ When validation fails, `errors` is automatically added:
1216
1620
 
1217
1621
  {
1218
1622
 
1219
- statusCode: 422,
1623
+   statusCode: 422,
1220
1624
 
1221
- valid: false,
1625
+   valid: false,
1222
1626
 
1223
- message: "Payload validation failed",
1627
+   message: "Payload validation failed",
1224
1628
 
1225
- errors: [
1629
+   errors: [
1226
1630
 
1227
- {
1631
+     {
1228
1632
 
1229
- path: "email",
1633
+       path: "email",
1230
1634
 
1231
- code: "INVALID_EMAIL",
1635
+       code: "INVALID_EMAIL",
1232
1636
 
1233
- message:
1637
+       message:
1234
1638
 
1235
- "Invalid email format for attribute email"
1639
+         "Invalid email format for attribute email"
1236
1640
 
1237
- }
1641
+     }
1238
1642
 
1239
- ]
1643
+   ]
1240
1644
 
1241
1645
  }
1242
-
1243
1646
  ```
1244
1647
 
1245
1648
  ### Custom Valid and Invalid Responses Together
@@ -1279,7 +1682,6 @@ automatically adds either:
1279
1682
  ```text
1280
1683
 
1281
1684
  validatedPayload
1282
-
1283
1685
  ```
1284
1686
 
1285
1687
  for successful validation, or:
@@ -1287,7 +1689,6 @@ for successful validation, or:
1287
1689
  ```text
1288
1690
 
1289
1691
  errors
1290
-
1291
1692
  ```
1292
1693
 
1293
1694
  for failed validation.
@@ -1302,18 +1703,17 @@ is:
1302
1703
 
1303
1704
  {
1304
1705
 
1305
- statusCode: 200,
1706
+   statusCode: 200,
1306
1707
 
1307
- valid: true,
1708
+   valid: true,
1308
1709
 
1309
- validatedPayload: {
1710
+   validatedPayload: {
1310
1711
 
1311
- *// validated fields*
1712
+     **// validated fields**
1312
1713
 
1313
- }
1714
+   }
1314
1715
 
1315
1716
  }
1316
-
1317
1717
  ```
1318
1718
 
1319
1719
  The default invalid response is:
@@ -1322,28 +1722,27 @@ The default invalid response is:
1322
1722
 
1323
1723
  {
1324
1724
 
1325
- statusCode: 400,
1725
+   statusCode: 400,
1326
1726
 
1327
- valid: false,
1727
+   valid: false,
1328
1728
 
1329
- message: "One or more attribute values are invalid",
1729
+   message: "One or more attribute values are invalid",
1330
1730
 
1331
- errors: [
1731
+   errors: [
1332
1732
 
1333
- {
1733
+     {
1334
1734
 
1335
- path: "field",
1735
+       path: "field",
1336
1736
 
1337
- code: "ERROR_CODE",
1737
+       code: "ERROR_CODE",
1338
1738
 
1339
- message: "Validation error message"
1739
+       message: "Validation error message"
1340
1740
 
1341
- }
1741
+     }
1342
1742
 
1343
- ]
1743
+   ]
1344
1744
 
1345
1745
  }
1346
-
1347
1746
  ```
1348
1747
 
1349
1748
  ## Nested Objects and Array Field Paths
@@ -1372,14 +1771,13 @@ An error can be returned as:
1372
1771
 
1373
1772
  {
1374
1773
 
1375
- path: "email",
1774
+   path: "email",
1376
1775
 
1377
- code: "INVALID_EMAIL",
1776
+   code: "INVALID_EMAIL",
1378
1777
 
1379
- message: "Invalid email format for attribute email"
1778
+   message: "Invalid email format for attribute email"
1380
1779
 
1381
1780
  }
1382
-
1383
1781
  ```
1384
1782
 
1385
1783
  ### Nested Object
@@ -1436,16 +1834,15 @@ its complete nested path:
1436
1834
 
1437
1835
  {
1438
1836
 
1439
- path: "address.location.latitude",
1837
+   path: "address.location.latitude",
1440
1838
 
1441
- code: "INVALID_TYPE",
1839
+   code: "INVALID_TYPE",
1442
1840
 
1443
- message:
1841
+   message:
1444
1842
 
1445
- "Invalid type for attribute address.location.latitude, required number value"
1843
+     "Invalid type for attribute address.location.latitude, required number value"
1446
1844
 
1447
1845
  }
1448
-
1449
1846
  ```
1450
1847
 
1451
1848
  Nested paths use dot notation:
@@ -1457,7 +1854,6 @@ address.city
1457
1854
  address.location.latitude
1458
1855
 
1459
1856
  address.location.longitude
1460
-
1461
1857
  ```
1462
1858
 
1463
1859
  ### Array Elements
@@ -1492,16 +1888,15 @@ The invalid third element is reported as:
1492
1888
 
1493
1889
  {
1494
1890
 
1495
- path: "marks[2]",
1891
+   path: "marks[2]",
1496
1892
 
1497
- code: "OUT_OF_RANGE",
1893
+   code: "OUT_OF_RANGE",
1498
1894
 
1499
- message:
1895
+   message:
1500
1896
 
1501
- "Attribute marks[2] should have a value between 0 and 100"
1897
+     "Attribute marks[2] should have a value between 0 and 100"
1502
1898
 
1503
1899
  }
1504
-
1505
1900
  ```
1506
1901
 
1507
1902
  Array paths use zero-based indexes:
@@ -1513,9 +1908,10 @@ marks[0]
1513
1908
  marks[1]
1514
1909
 
1515
1910
  marks[2]
1516
-
1517
1911
  ```
1518
1912
 
1913
+ Array-level constraints such as `minItems` and `maxItems` report the path of the array itself. For nested arrays, the complete parent path is retained, for example `orders[1].items`.
1914
+
1519
1915
  ### Nested Fields Inside Arrays
1520
1916
 
1521
1917
  Paths can also identify fields inside array elements.
@@ -1529,7 +1925,6 @@ products[0].quantity
1529
1925
  products[1].quantity
1530
1926
 
1531
1927
  products[2].price
1532
-
1533
1928
  ```
1534
1929
 
1535
1930
  This provides enough information for consumers to identify the exact
@@ -1574,391 +1969,387 @@ Result:
1574
1969
 
1575
1970
  {
1576
1971
 
1577
- "email": "Invalid email format for attribute email",
1972
+   "email": "Invalid email format for attribute email",
1578
1973
 
1579
- "address.location.latitude": "Invalid type for attribute address.location.latitude, required number value",
1974
+   "address.location.latitude": "Invalid type for attribute address.location.latitude, required number value",
1580
1975
 
1581
- "marks[2]": "Attribute marks[2] should have a value between 0 and 100"
1976
+   "marks[2]": "Attribute marks[2] should have a value between 0 and 100"
1582
1977
 
1583
1978
  }
1584
-
1585
1979
  ```
1586
1980
 
1587
- ## Examples And Usage
1981
+ ## Examples and Usage
1588
1982
 
1589
1983
  ### Sample Validation Rule
1590
1984
 
1591
1985
  sample-1
1592
1986
 
1593
- ```javascript
1987
+ ```js
1594
1988
 
1595
1989
  {
1596
1990
 
1597
- firstName: {
1991
+   firstName: {
1598
1992
 
1599
- mandatory: true,
1993
+     mandatory: true,
1600
1994
 
1601
- allowNull: false,
1995
+     allowNull: false,
1602
1996
 
1603
- type: "string",
1997
+     type: "string",
1604
1998
 
1605
- minLength: 3,
1999
+     minLength: 3,
1606
2000
 
1607
- minLengthError:"First name must have minimum 3 characters."
2001
+     minLengthError: "First name must have minimum 3 characters."
1608
2002
 
1609
- },
2003
+   },
1610
2004
 
1611
- lastName: {
2005
+   lastName: {
1612
2006
 
1613
- mandatory: false,
2007
+     mandatory: false,
1614
2008
 
1615
- allowNull: true,
2009
+     allowNull: true,
1616
2010
 
1617
- type: "string",
2011
+     type: "string",
1618
2012
 
1619
- },
2013
+   },
1620
2014
 
1621
- email: {
2015
+   email: {
1622
2016
 
1623
- mandatory: true,
2017
+     mandatory: true,
1624
2018
 
1625
- allowNull: false,
2019
+     allowNull: false,
1626
2020
 
1627
- type: "email",
2021
+     type: "email",
1628
2022
 
1629
- },
2023
+   },
1630
2024
 
1631
- phone: {
2025
+   phone: {
1632
2026
 
1633
- mandatory: true,
2027
+     mandatory: true,
1634
2028
 
1635
- allowNull: false,
2029
+     allowNull: false,
1636
2030
 
1637
- type: "string",
2031
+     type: "string",
1638
2032
 
1639
- },
2033
+   },
1640
2034
 
1641
- age: {
2035
+   age: {
1642
2036
 
1643
- mandatory: false,
2037
+     mandatory: false,
1644
2038
 
1645
- type: "number",
2039
+     type: "number",
1646
2040
 
1647
- min: 1,
2041
+     min: 1,
1648
2042
 
1649
- max: 120,
2043
+     max: 120,
1650
2044
 
1651
- },
2045
+   },
1652
2046
 
1653
2047
  };
1654
-
1655
2048
  ```
1656
2049
 
1657
2050
  sample-2
1658
2051
 
1659
- ```javascript
2052
+ ```js
1660
2053
 
1661
2054
  {
1662
2055
 
1663
- id: {
2056
+   id: {
1664
2057
 
1665
- mandatory: true,
2058
+     mandatory: true,
1666
2059
 
1667
- allowNull: true,
2060
+     allowNull: true,
1668
2061
 
1669
- type: "uuidv4",
2062
+     type: "uuidv4",
1670
2063
 
1671
- },
2064
+   },
1672
2065
 
1673
- batchId: {
2066
+   batchId: {
1674
2067
 
1675
- mandatory: true,
2068
+     mandatory: true,
1676
2069
 
1677
- allowNull: true,
2070
+     allowNull: true,
1678
2071
 
1679
- type: "objectId",
2072
+     type: "objectId",
1680
2073
 
1681
- },
2074
+   },
1682
2075
 
1683
- firstName: {
2076
+   firstName: {
1684
2077
 
1685
- mandatory: true,
2078
+     mandatory: true,
1686
2079
 
1687
- type: "string",
2080
+     type: "string",
1688
2081
 
1689
- minLength: 3,
2082
+     minLength: 3,
1690
2083
 
1691
- },
2084
+   },
1692
2085
 
1693
- lastName: {
2086
+   lastName: {
1694
2087
 
1695
- mandatory: false,
2088
+     mandatory: false,
1696
2089
 
1697
- allowNull: true,
2090
+     allowNull: true,
1698
2091
 
1699
- type: "string",
2092
+     type: "string",
1700
2093
 
1701
- },
2094
+   },
1702
2095
 
1703
- age: {
2096
+   age: {
1704
2097
 
1705
- type: "number",
2098
+     type: "number",
1706
2099
 
1707
- min: 0.1,
2100
+     min: 0.1,
1708
2101
 
1709
- max: 120,
2102
+     max: 120,
1710
2103
 
1711
- },
2104
+   },
1712
2105
 
1713
- isAdult: {
2106
+   isAdult: {
1714
2107
 
1715
- type: "boolean",
2108
+     type: "boolean",
1716
2109
 
1717
- },
2110
+   },
1718
2111
 
1719
- totalWins: {
2112
+   totalWins: {
1720
2113
 
1721
- type: "number",
2114
+     type: "number",
1722
2115
 
1723
- min: 0,
2116
+     min: 0,
1724
2117
 
1725
- preventDecimal: true,
2118
+     preventDecimal: true,
1726
2119
 
1727
- },
2120
+   },
1728
2121
 
1729
- email: {
2122
+   email: {
1730
2123
 
1731
- regex: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$/,
2124
+     regex: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$/,
1732
2125
 
1733
- },
2126
+   },
1734
2127
 
1735
- githubLink: {
2128
+   githubLink: {
1736
2129
 
1737
- type: "url",
2130
+     type: "url",
1738
2131
 
1739
- },
2132
+   },
1740
2133
 
1741
- accountStatus: {
2134
+   accountStatus: {
1742
2135
 
1743
- type: "enum",
2136
+     type: "enum",
1744
2137
 
1745
- enumValues: ["Active", "Inactive", 200],
2138
+     enumValues: ["Active", "Inactive", 200],
1746
2139
 
1747
- },
2140
+   },
1748
2141
 
1749
- marks: {
2142
+   marks: {
1750
2143
 
1751
- range: "0-100",
2144
+     range: "0-100",
1752
2145
 
1753
- },
2146
+   },
1754
2147
 
1755
- allMarks: {
2148
+   allMarks: {
1756
2149
 
1757
- type: "array",
2150
+     type: "array",
1758
2151
 
1759
- allowEmptyArray: false,
2152
+     allowEmptyArray: false,
1760
2153
 
1761
- elementConstraints: {
2154
+     elementConstraints: {
1762
2155
 
1763
- type: "number",
2156
+       type: "number",
1764
2157
 
1765
- allowNull: false,
2158
+       allowNull: false,
1766
2159
 
1767
- range: "0-100",
2160
+       range: "0-100",
1768
2161
 
1769
- },
2162
+     },
1770
2163
 
1771
- },
2164
+   },
1772
2165
 
1773
- totalScore: {
2166
+   totalScore: {
1774
2167
 
1775
- type: "number",
2168
+     type: "number",
1776
2169
 
1777
- dependency: {
2170
+     dependency: {
1778
2171
 
1779
- result: {
2172
+       result: {
1780
2173
 
1781
- setDependencyRule: (totalScore, result) => {
2174
+         setDependencyRule: (totalScore, result) => {
1782
2175
 
1783
- return { mandatory: true, allowNull: false, type: "string" };
2176
+           return { mandatory: true, allowNull: false, type: "string" };
1784
2177
 
1785
- },
2178
+         },
1786
2179
 
1787
- },
2180
+       },
1788
2181
 
1789
- },
2182
+     },
1790
2183
 
1791
- },
2184
+   },
1792
2185
 
1793
- result: {
2186
+   result: {
1794
2187
 
1795
- type: "string",
2188
+     type: "string",
1796
2189
 
1797
- dependency: {
2190
+     dependency: {
1798
2191
 
1799
- totalScore: {
2192
+       totalScore: {
1800
2193
 
1801
- setDependencyRule: (result, totalScore) => {
2194
+         setDependencyRule: (result, totalScore) => {
1802
2195
 
1803
- return { mandatory: true, allowNull: false, type: "number" };
2196
+           return { mandatory: true, allowNull: false, type: "number" };
1804
2197
 
1805
- },
2198
+         },
1806
2199
 
1807
- },
2200
+       },
1808
2201
 
1809
- },
2202
+     },
1810
2203
 
1811
- },
2204
+   },
1812
2205
 
1813
- minSalary: {
2206
+   minSalary: {
1814
2207
 
1815
- mandatory: true,
2208
+     mandatory: true,
1816
2209
 
1817
- min: 1,
2210
+     min: 1,
1818
2211
 
1819
- type: "number",
2212
+     type: "number",
1820
2213
 
1821
- dependency: {
2214
+     dependency: {
1822
2215
 
1823
- maxSalary: {
2216
+       maxSalary: {
1824
2217
 
1825
- setDependencyRule: (minSalary, maxSalary) => {
2218
+         setDependencyRule: (minSalary, maxSalary) => {
1826
2219
 
1827
- return {
2220
+           return {
1828
2221
 
1829
- mandatory: true,
2222
+             mandatory: true,
1830
2223
 
1831
- min: minSalary + 1,
2224
+             min: minSalary + 1,
1832
2225
 
1833
- minError: "maxSalary must be more than minSalary",
2226
+             minError: "maxSalary must be more than minSalary",
1834
2227
 
1835
- };
2228
+           };
1836
2229
 
1837
- },
2230
+         },
1838
2231
 
1839
- },
2232
+       },
1840
2233
 
1841
- },
2234
+     },
1842
2235
 
1843
- },
2236
+   },
1844
2237
 
1845
- maxSalary: {
2238
+   maxSalary: {
1846
2239
 
1847
- dependency: {
2240
+     dependency: {
1848
2241
 
1849
- minSalary: {
2242
+       minSalary: {
1850
2243
 
1851
- setDependencyRule: (maxSalary, minSalary) => {
2244
+         setDependencyRule: (maxSalary, minSalary) => {
1852
2245
 
1853
- return {
2246
+           return {
1854
2247
 
1855
- mandatory: true,
2248
+             mandatory: true,
1856
2249
 
1857
- max: maxSalary - 1,
2250
+             max: maxSalary - 1,
1858
2251
 
1859
- maxError: "minSalary must be less than maxSalary",
2252
+             maxError: "minSalary must be less than maxSalary",
1860
2253
 
1861
- };
2254
+           };
1862
2255
 
1863
- },
2256
+         },
1864
2257
 
1865
- },
2258
+       },
1866
2259
 
1867
- },
2260
+     },
1868
2261
 
1869
- },
2262
+   },
1870
2263
 
1871
- address: {
2264
+   address: {
1872
2265
 
1873
- mandatory: true,
2266
+     mandatory: true,
1874
2267
 
1875
- type: "object",
2268
+     type: "object",
1876
2269
 
1877
- allowEmptyObject: false,
2270
+     allowEmptyObject: false,
1878
2271
 
1879
- objectAttr: {
2272
+     objectAttr: {
1880
2273
 
1881
- country: { mandatory: true, type: "string" },
2274
+       country: { mandatory: true, type: "string" },
1882
2275
 
1883
- state: {
2276
+       state: {
1884
2277
 
1885
- mandatory: true,
2278
+         mandatory: true,
1886
2279
 
1887
- type: "string",
2280
+         type: "string",
1888
2281
 
1889
- },
2282
+       },
1890
2283
 
1891
- city: {},
2284
+       city: {},
1892
2285
 
1893
- zip: {
2286
+       zip: {
1894
2287
 
1895
- mandatory: true,
2288
+         mandatory: true,
1896
2289
 
1897
- type: "string",
2290
+         type: "string",
1898
2291
 
1899
- },
2292
+       },
1900
2293
 
1901
- position: {
2294
+       position: {
1902
2295
 
1903
- mandatory: true,
2296
+         mandatory: true,
1904
2297
 
1905
- type: "object",
2298
+         type: "object",
1906
2299
 
1907
- allowEmptyObject: false,
2300
+         allowEmptyObject: false,
1908
2301
 
1909
- objectAttr: {
2302
+         objectAttr: {
1910
2303
 
1911
- lattitude: { mandatory: true, type: "number" },
2304
+           lattitude: { mandatory: true, type: "number" },
1912
2305
 
1913
- longitude: {
2306
+           longitude: {
1914
2307
 
1915
- mandatory: true,
2308
+             mandatory: true,
1916
2309
 
1917
- type: "number",
2310
+             type: "number",
1918
2311
 
1919
- },
2312
+           },
1920
2313
 
1921
- },
2314
+         },
1922
2315
 
1923
- },
2316
+       },
1924
2317
 
1925
- },
2318
+     },
1926
2319
 
1927
- },
2320
+   },
1928
2321
 
1929
2322
  }
1930
-
1931
2323
  ```
1932
2324
 
1933
2325
  ### Usage
1934
2326
 
1935
- #### creating your route with payload validation middleware
2327
+ #### Creating a route with payload validation middleware
1936
2328
 
1937
- ```javascript
2329
+ ```js
1938
2330
 
1939
- *//Here validatePayload is your middleware function, where you're invoking perfect payload*
2331
+ **// validatePayload is the middleware that invokes perfectPayload()**
1940
2332
 
1941
2333
  router.post(
1942
2334
 
1943
- "/payload-validation",
2335
+   "/payload-validation",
1944
2336
 
1945
- validatePayload({ rule: <your validation rule json object> }),
2337
+   validatePayload({ rule: <your validation rule json object> }),
1946
2338
 
1947
- (req, res) => res.send("OK")
2339
+   (req, res) => res.send("OK")
1948
2340
 
1949
2341
  );
1950
-
1951
2342
  ```
1952
2343
 
1953
- #### 1 Use perfect-payload in your middleware like below(for MODULE JS)
2344
+ #### ES Modules middleware example
1954
2345
 
1955
- ```javascript
1956
- import { perfectPayloadV1 } from "perfect-payload";
2346
+ ```js
2347
+ import { perfectPayload } from "perfect-payload";
1957
2348
 
1958
2349
  export const validatePayload = ({ rule }) => {
1959
2350
  return (req, res, next) => {
1960
2351
  try {
1961
- const { statusCode, ...response } = perfectPayloadV1(req?.body, rule);
2352
+ const { statusCode, ...response } = perfectPayload(req?.body, rule);
1962
2353
 
1963
2354
  if (+statusCode >= 200 && +statusCode <= 299) {
1964
2355
  req.validatedBody = response?.validatedPayload;
@@ -1974,15 +2365,15 @@ export const validatePayload = ({ rule }) => {
1974
2365
  };
1975
2366
  ```
1976
2367
 
1977
- #### 2 Use perfect-payload in your middleware like below(for COMMON JS)
2368
+ #### CommonJS middleware example
1978
2369
 
1979
- ```javascript
2370
+ ```js
1980
2371
  function validatePayload({ rule }) {
1981
2372
  return async (req, res, next) => {
1982
2373
  try {
1983
- const { perfectPayloadV1 } = await import("perfect-payload");
2374
+ const { perfectPayload } = await import("perfect-payload");
1984
2375
 
1985
- const { statusCode, ...response } = perfectPayloadV1(req?.body, rule);
2376
+ const { statusCode, ...response } = perfectPayload(req?.body, rule);
1986
2377
 
1987
2378
  if (+statusCode >= 200 && +statusCode <= 299) {
1988
2379
  req.validatedBody = response?.validatedPayload;
@@ -2002,7 +2393,7 @@ function validatePayload({ rule }) {
2002
2393
  module.exports = { validatePayload };
2003
2394
  ```
2004
2395
 
2005
- **---**
2396
+ ---
2006
2397
 
2007
2398
  This documentation provides a comprehensive guide to using the data
2008
2399