rich json validator
npm install perfect-payloadjavascript
import { perfectPayloadV1 } from "perfect-payload";
const { statucCode = 400, ...result } = perfectPayloadV1(
data,
dataValidationRule,
validPayloadResponse,
inValidPayloadResponse
);
`
input:
1. data : your payload object (required \*)
2. dataValidationRule: validation rule object (required \*)
3. validPayloadResponse: response object you want it back on all validation passed (Optional)
4. inValidPayloadResponse: response object you want it back on any validation fails (Optional)
Default Valid Payload Response:
`javascript
{
statusCode:200,
valid:true,
validatedPayload:{...}
}
`
Note: you can use validatedPayload to overwrite your existing req.body or create new req attribute(req.validatedBody=validatedPayload) to access in your API logic
Default Invalid Payload Response:
`javascript
{
statusCode:400,
valid:false,
message:"One or more attribute values are invalid",
errors:["minSalary must be less than maxSalary"]
}
`
Note: If inValidPayloadResponse is passed, then it will be returned along with errors property(avoid error attribute in your inValidPayloadResponse object)
2. Available Validation Attributes
These attributes define the rules that can be applied to each field in the data object:
- mandatory: Specifies whether the data is required.
- allowNull: Allows null values.
- allowEmptyObject: Allows empty objects {}.
- allowEmptyArray: Allows empty arrays [].
- elementConstraints: Defines the constraints of elements in an array (refer to Available Attributes section).
- regex: Applies custom regular expression validation.
- type: Specifies the type of the field (refer to Available Types section).
- minLength: Minimum length for string values.
- maxLength: Maximum length for string values.
- preventDecimal: Disallows decimal or fractional values.
- min: Specifies the minimum number value.
- max: Specifies the maximum number value.
- range: Specifies a numeric range for the value.
- objectAttr: Validates nested objects.
- dependency: Validates fields that depend on the values of other fields (e.g., min and max salary).
3. Available Types
These types can be used in the type attribute to specify the expected data type:
- number: Numeric values.
- string: String values.
- boolean: Boolean values (true/false).
- email: Valid email addresses.
- url: Valid URL formats.
- enum: A specific set of allowed values (supports heterogeneous arrays).
- uuid: Valid UUIDs (supports all versions).
- uuidv1/uuidv3/uuidv4/uuidv5: Version-specific UUID validation.
- objectId: Valid MongoDB ObjectIds.
- array: Validates arrays, with support for element type validation using elementConstraints.
- object: Validates objects, including nested objects using objectAttr.
4. Custom Error Message Attributes
You can define custom error messages for various validation failures using these attributes:
- mandatoryError: Custom message when a mandatory field is missing.
- allowNullError: Custom message when a null value is not allowed.
- emptyObjectError: Custom message when an empty object {} is not allowed.
- emptyArrayError: Custom message when an empty array [] is not allowed.
- elementConstraintsError: Custom message when array elements do not match the passed constraints.
- regexError: Custom message when a value does not match the specified regex pattern.
- typeError: Custom message when a value does not match the specified type.
- minLengthError: Custom message when a string value is shorter than the minimum length.
- maxLengthError: Custom message when a string value exceeds the maximum length.
- preventDecimalError: Custom message when a decimal value is not allowed.
- minError: Custom message when a value is less than the minimum allowed.
- maxError: Custom message when a value exceeds the maximum allowed.
- rangeError: Custom message when a value is outside the specified range.
5. Default Values
If not explicitly specified, the following default values are applied:
- mandatory: false (field is not required).
- allowNull: true (allows null values).
- allowEmptyObject: true (allows empty objects {}).
- allowEmptyArray: true (allows empty arrays []).
- elementConstraints: Ignored.
- regex: Ignored.
- type: Ignored.
- minLength: Ignored.
- maxLength: Ignored.
- preventDecimal: false (allows both decimal and integer values).
- min: Ignored.
- max: Ignored.
- range: Ignored.
- objectAttr: Ignored.
- dependency: Ignored.
6. Examples And Usage
$3
sample-1
`javascript
{
firstName: {
mandatory: true,
allowNull: false,
type: "string",
minLength: 3,
minLengthError:"First name must have minimum 3 characters."
},
lastName: {
mandatory: false,
allowNull: true,
type: "string",
},
email: {
mandatory: true,
allowNull: false,
type: "email",
},
phone: {
mandatory: true,
allowNull: false,
type: "string",
},
age: {
mandatory: false,
type: "number",
min: 1,
max: 120,
},
};
`
sample-2
`javascript
{
id: {
mandatory: true,
allowNull: true,
type: "uuidv4",
},
batchId: {
mandatory: true,
allowNull: true,
type: "objectId",
},
firstName: {
mandatory: true,
type: "string",
minLength: 3,
},
lastName: {
mandatory: false,
allowNull: true,
type: "string",
},
age: {
type: "number",
min: 0.1,
max: 120,
},
isAdult: {
type: "boolean",
},
totalWins: {
type: "number",
min: 0,
preventDecimal: true,
},
email: {
regex: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
},
githubLink: {
type: "url",
},
accountStatus: {
type: "enum",
enumValues: ["Active", "Inactive", 200],
},
marks: {
range: "0-100",
},
allMarks: {
type: "array",
allowEmptyArray: false,
elementConstraints: {
type: "number",
allowNull: false,
range: "0-100",
},
},
totalScore: {
type: "number",
dependency: {
result: {
setDependencyRule: (totalScore, result) => {
return { mandatory: true, allowNull: false, type: "string" };
},
},
},
},
result: {
type: "string",
dependency: {
totalScore: {
setDependencyRule: (result, totalScore) => {
return { mandatory: true, allowNull: false, type: "number" };
},
},
},
},
minSalary: {
mandatory: true,
min: 1,
type: "number",
dependency: {
maxSalary: {
setDependencyRule: (minSalary, maxSalary) => {
return {
mandatory: true,
min: minSalary + 1,
minError: "maxSalary must be more than minSalary",
};
},
},
},
},
maxSalary: {
dependency: {
minSalary: {
setDependencyRule: (maxSalary, minSalary) => {
return {
mandatory: true,
max: maxSalary - 1,
maxError: "minSalary must be less than maxSalary",
};
},
},
},
},
address: {
mandatory: true,
type: "object",
allowEmptyObject: false,
objectAttr: {
country: { mandatory: true, type: "string" },
state: {
mandatory: true,
type: "string",
},
city: {},
zip: {
mandatory: true,
type: "string",
},
position: {
mandatory: true,
type: "object",
allowEmptyObject: false,
objectAttr: {
lattitude: { mandatory: true, type: "number" },
longitude: {
mandatory: true,
type: "number",
},
},
},
},
},
}
`
$3
#### 1. creating your route with payload validation middleware
`javascript
//Here validatePayload is your middleware function, where you're invoking perfect payload
router.post(
"/payload-validation",
validatePayload({ rule: }),
(req, res) => res.send("OK")
);
`
#### 2.1 Use perfect-payload in your middleware like below(for MODULE JS)
`javascript
import { perfectPayloadV1 } from "perfect-payload";
export const validatePayload = ({ rule }) => {
return (req, res, next) => {
try {
const { statusCode, ...response } = perfectPayloadV1(req?.body, rule);
if (+statusCode >= 200 && +statusCode <= 299) {
req.validatedBody=response?.validatedPayload
next();
} else res.status(statusCode).json(response);
} catch (error) {
console.error("Error validating payload", error);
res.status(500).json({ error: "Internal Server Error" });
}
};
};
`
#### 2.2 Use perfect-payload in your middleware like below(for COMMON JS)
`javascript
function validatePayload({ rule }) {
return async (req, res, next) => {
try {
const { perfectPayloadV1 } = await import("perfect-payload");
const { statusCode, ...response } = perfectPayloadV1(req?.body, rule);
if (+statusCode >= 200 && +statusCode <= 299) {
req.validatedBody=response?.validatedPayload
next();
} else {
res.status(statusCode).json(response);
}
} catch (error) {
console.error("Error validating payload", error);
res.status(500).json({ error: "Internal Server Error" });
}
};
}
module.exports = { validatePayload };
``