New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support multiple custom validators/sanitisers with schemas #552
Comments
I would like to be able to have such a possibility as well |
I have left an API suggestion in another issue which would tangentially solve this problem. Let me know what you think. |
For those that need a work around for now this should help. /**
* Runs an array of validators over a value
*/
const validationArray = validators => {
let errors = [];
return {
custom: {
errorMessage: () => {
return errors.length >= 1 ? errors.join('\n') : 'value is invalid';
},
options: (value, opts) => {
errors = [];
const results = validators.map((validator, index) => {
logger.debug(`validating ${value} [${index + 1}/${validators.length}]`);
const result = validator.validate(value, opts);
// If validation failed set current Error
if (result === false) {
const errorMessage = validator.errorMessage || `${value} is invalid`;
logger.debug(`setting error to ${errorMessage}`);
errors.push(errorMessage);
}
return result;
});
return results.every(value => value === true);
}
}
};
}; To use it pass an array of functions that return a validate field and optionally an /**
* Ensures field value is from provided array
*/
const oneOf = array => ({
errorMessage: `value must be one of [${array.join(', ').replace(/, ([^,]*)$/, ' or $1')}]`,
validate: value => array.includes(value)
});
/**
* Ensures field value is boolean
*/
const isBoolean = {
validate: value => typeof value === 'boolean'
};
/**
* Schema
*/
export const schema = {
type: {
in: ['params'],
...validationArray([
isBoolean,
oneOf([
'virtual',
'ipv4',
'ipv6'
])
])
}
}; |
You can do multiple validations in the "custom" prop function isValidPhone() {
}
function anotherValidation() {
}
Validation.testSchema= {
'user.phone': {
in: ['body'],
custom: {
options(value, { req, location, path }) {
if (!isValidPhone(value)) {
this.message = 'Invalid phone';
return false;
} else if (!anotherValidation(value)) {
this.message = 'Invalid validation';
return false;
}
return true;
},
},
errorMessage: 'Phone id required',
},
}; |
Previously, we would sanitize the input SIN to remove spaces or hyphens before validating it. Unfortunately, sanitizing it would also change mutate the submitted value, so repopulating the form would show an error but then a potentially a value that they never typed in. Like if I submitted "123 456 78", it would come back as "12345678". So it's telling me I'm wrong, but it also rewrote what I sent in. That's not really fair. Changed the SIN validation to _only_ use our custom validation method and send back the same error messages. The code is uglier but it has tests now, so should be okay. Behaviour should be the same as previously. Also, added an underscore to my internal functions because they're supposed to be private. Inspired by @OmgImAlexis' comment 👇 Source: - express-validator/express-validator#552 (comment)
Previously, we would sanitize the input SIN to remove spaces or hyphens before validating it. Unfortunately, sanitizing it would also mutate the submitted value, so repopulating the form would show them a validation error and then a value they probably never typed in. Like if I submitted "123 456 78", it would come back as "12345678". So it's telling me I'm wrong, but it also rewrote what I sent in. That's not really fair. Changed the SIN validation to _only_ use our custom validation method and send back the same error messages. The code is uglier but it has tests now, so should be okay. Behaviour should be the same as previously. Also, added an underscore to my internal functions because they're supposed to be private. Inspired by @OmgImAlexis' comment 👇 Source: - express-validator/express-validator#552 (comment)
This is a workaround I use. 'use strict';
const expressValidator = require('express-validator');
const customValidators = require('./custom-validators');
for (const [name, fn] of Object.entries(customValidators)) {
if (!expressValidator.validator[name]) {
expressValidator.validator[name] = fn;
}
} Require extend.js before your routes |
This comment was marked as off-topic.
This comment was marked as off-topic.
Multiple validation can be used by following schema. Also bail can be used to stop validation on error.
My package.json
I guess, this is what you all are looking for. |
Workaround to have multiple custom validators with their own error message, const validationMiddleware = validator.checkSchema({
titleLabel: {
in: 'body',
isString: {
errorMessage: 'titleLabel name must be a string'
},
custom: {
options: (value, params) => {
// Custom Validator 1
if (!isSafe(value)) {
params.errorMessage = 'titleLabel has malicious content'
return false
}
// Custom Validator 2
if (hasRestrictedChars(value)) {
params.errorMessage = 'titleLabel has restricted characters'
return false
}
return true
},
errorMessage: (_, params) => {
if (params.errorMessage) {
return params.errorMessage
}
return 'Invalid titleLabel'
}
}
}
}) |
We can't use multiple custom validators/sanitisers when we use schemas, as an object can't have multiple keys with the same name.
This makes it impossible to break them into smaller pieces of validation/sanitisation.
Example taken from #550: one that does only email DNS validation, another one that does only email availability validation, etc.
The only way I can imagine for now is to accept an array of custom validators.
Any other suggestions are welcome.
The text was updated successfully, but these errors were encountered: