light-express-validator
Version:
A super lightweight express validation inspired by Laravel validation.
106 lines (100 loc) • 3.34 kB
JavaScript
const ValidationError = require('./ValidationError');
const {
isEmpty,
meetMinLength,
meetMaxLength,
isNumeric,
isDecimal,
isBoolean,
isValidDate,
isValidEmail,
isImageFromBuffer,
} = require('./utils/validation');
function validate(toValidate) {
return function (req, res, next) {
try {
iterateFields({ toValidate, payload: req.body, file: req.file });
next();
} catch (error) {
if (error instanceof ValidationError) {
return res.status(400).json(error);
}
next(error);
}
};
}
/**
* Iterate through the fields.
* @param {Object} obj - The input object.
* @param {Array} obj.toValidate - The object validation. ({ name: 'required|min:8|max:8' }).
* @param {String} obj.payload - The payload (req.body).
* @returns {Boolean|Error} Return validation message or false if the data valid within rules.
*/
function iterateFields({ toValidate, payload, file }) {
const fields = Object.keys(toValidate);
const error = new ValidationError('Form validation failed');
for (const field of fields) {
const rules = toValidate[field].split('|');
const data = payload[field];
const msg = iterateRules({ rules, field, data, file });
if (msg) {
error.addFieldError(field, msg);
}
}
if (Object.keys(error.fields).length) {
throw error;
}
}
/**
* Iterate through the rules and validate it data within the given rules.
* @param {Object} obj - The input object.
* @param {Array} obj.rules - The array of rules to check againt (['required', 'min:8']).
* @param {String} obj.field - The payload field.
* @param {String} obj.data - The payload data to validate.
* @returns {Boolean|Error} Return validation message or false if the data valid within rules.
*/
function iterateRules({ rules, field, data, file }) {
for (const rule of rules) {
if (rule === 'required' && isEmpty(data)) {
return `The ${field} field is required.`;
}
if (/^min:/.test(rule)) {
const length = rule.split(':').at(-1);
if (!meetMinLength(data, length)) {
return `The ${field} field must be at least ${length} characters.`;
}
}
if (/^max:/.test(rule)) {
const length = rule.split(':').at(-1);
if (!meetMaxLength(data, length)) {
return `The ${field} field must be at most ${length} characters.`;
}
}
if (rule === 'numeric' && !isNumeric(data)) {
return `The ${field} field must be a number.`;
}
if (rule === 'integer' && !Number.isInteger(data)) {
return `The ${field} field must be an integer.`;
}
if (/^decimal:/.test(rule)) {
const decimal = rule.split(':').at(-1);
if (!isDecimal(data, decimal)) {
return `The ${field} field must have ${decimal} decimal places.`;
}
}
if (rule === 'boolean' && !isBoolean(data)) {
return `The ${field} field must be true or false.`;
}
if (rule === 'date' && !isValidDate(data)) {
return `The ${field} field must be a valid date.`;
}
if (rule === 'email' && !isValidEmail(data)) {
return `The ${field} field must be a valid email address.`;
}
if (rule === 'image' && file && !isImageFromBuffer(file.buffer).isImage) {
return `The ${field} field must be an image.`;
}
}
return undefined;
}
module.exports = validate;