Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

express-validator

Package Overview
Dependencies
Maintainers
3
Versions
121
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-validator - npm Package Compare versions

Comparing version 3.2.1 to 4.0.0

check/check-all.js

394

index.d.ts

@@ -7,4 +7,11 @@ // Type definitions for express-validator 3.0.0

///<reference types="express"/>
///<reference types="bluebird"/>
import * as express from 'express';
import {
Dictionary,
Result,
MappedError,
Options,
Validator as BaseValidator
} from './shared-typings';
// Add RequestValidation Interface on to Express's Request Interface.

@@ -21,3 +28,3 @@ declare global {

*/
declare function ExpressValidator(options?: ExpressValidator.Options.ExpressValidatorOptions): express.RequestHandler;
declare function ExpressValidator(options?: Options.ExpressValidatorOptions): express.RequestHandler;
export = ExpressValidator;

@@ -37,5 +44,5 @@ // Internal Module.

[param: string]:
ExpressValidator.Options.ValidationSchemaParamOptions // standard validators
Options.ValidationSchemaParamOptions // standard validators
| // or
{ [customValidator: string]: ExpressValidator.Options.ValidatorSchemaOptions } // custom ones
{ [customValidator: string]: Options.ValidatorSchemaOptions } // custom ones
}

@@ -53,33 +60,2 @@

interface SanitizerFunction { (item: string): Sanitizer; }
interface Dictionary<T> { [key: string]: T; }
interface Result {
/**
* @return A boolean determining whether there were errors or not.
*/
isEmpty(): boolean
/**
* @return All errors for all validated parameters will be included, unless you specify that you want only the first
* error of each param by invoking `result.useFirstErrorOnly()`.
*/
array(): MappedError[]
/**
* @return An object of errors, where the key is the parameter name, and the value is an error object as returned by
* the error formatter.
* Because of historical reasons, by default this method will return the last error of each parameter.
* You can change this behavior by invoking result.useFirstErrorOnly(), so the first error is returned instead.
*/
mapped(): Dictionary<MappedError>
/**
* Sets the `firstErrorOnly` flag of this result object, which modifies the way other methods like `result.array()`
* and `result.mapped()` work.
*/
useFirstErrorOnly(): Result
/**
* Useful for dealing with the validation errors in the catch block of a try..catch or promise.
*
* @throws If there are errors, throws an Error object which is decorated with the same API as the validation
* result object.
*/
throw(): Result
}

@@ -132,109 +108,7 @@ export interface RequestValidation {

export interface Validator {
export interface Validator extends BaseValidator {
// Additional legacy validators
/*
* Hi fellow contributor,
* TODO if you add a validator here, please add it also to ValidationSchemaParamOptions
* preferably in the same order/position, just to make it easier for comparision.
*/
isEmail(options?: ExpressValidator.Options.IsEmailOptions): Validator;
isURL(options?: ExpressValidator.Options.IsURLOptions): Validator;
isMACAddress(): Validator;
/**
*
* @param version IP version number 4 or 6
*/
isIP(version?: IPVersion): Validator;
isFQDN(options?: ExpressValidator.Options.IsFQDNOptions): Validator;
isBoolean(): Validator;
/**
* @param locale Optional. Defaults to en-US
*/
isAlpha(locale?: AlphaLocale): Validator;
/**
* @param locale Optional. Defaults to en-US
*/
isAlphanumeric(locale?: AlphanumericLocale): Validator;
isNumeric(): Validator;
isLowercase(): Validator;
isUppercase(): Validator;
isAscii(): Validator;
isFullWidth(): Validator;
isHalfWidth(): Validator;
isVariableWidth(): Validator;
isMultibyte(): Validator;
isSurrogatePair(): Validator;
isInt(options?: ExpressValidator.Options.IsIntOptions): Validator;
isFloat(options?: ExpressValidator.Options.MinMaxExtendedOptions): Validator;
isDecimal(): Validator;
isHexadecimal(): Validator;
isDivisibleBy(num: number): Validator;
isHexColor(): Validator;
isMD5(): Validator;
isJSON(): Validator;
isEmpty(): Validator;
isLength(options: ExpressValidator.Options.MinMaxOptions): Validator;
isByteLength(options: ExpressValidator.Options.MinMaxOptions): Validator;
/**
* @param version 3, 4, 5 or 'all'. Default is 'all'.
* @see http://en.wikipedia.org/wiki/Universally_unique_identifier
*/
isUUID(version?: UUIDVersion): Validator;
/**
* @see https://docs.mongodb.com/manual/reference/bson-types/#objectid
*/
isMongoId(): Validator;
isDate(): Validator;
/**
* @param date Optional. Default to now.
*/
isAfter(date?: Date): Validator;
/**
* @param date Optional. Default to now.
*/
isBefore(date?: Date): Validator;
isIn(options: string | string[]): Validator;
isCreditCard(): Validator;
isISIN(): Validator;
/**
* @param version
* @see https://en.wikipedia.org/wiki/International_Standard_Book_Number
*/
isISBN(version?: number): Validator;
/**
* @param options
* @see https://en.wikipedia.org/wiki/International_Standard_Serial_Number
*/
isISSN(options?: ExpressValidator.Options.IsISSNOptions): Validator
isMobilePhone(locale: MobilePhoneLocal): Validator;
isCurrency(options: ExpressValidator.Options.IsCurrencyOptions): Validator;
/**
* @see https://en.wikipedia.org/wiki/ISO_8601
*/
isISO8601(): Validator;
/**
* @see https://en.wikipedia.org/wiki/Base64
*/
isBase64(): Validator;
/**
* @see https://en.wikipedia.org/wiki/Data_URI_scheme
*/
isDataURI(): Validator;
isWhitelisted(chars: string | string[]): Validator;
// Additional Validators provided by validator.js
equals(equals: any): Validator;
contains(str: string): Validator;
matches(pattern: RegExp | string, modifiers?: string): Validator;
// Additional ValidatorChain.prototype.* validators
notEmpty(): Validator;
len(options: ExpressValidator.Options.MinMaxOptions): Validator;
optional(options?: ExpressValidator.Options.OptionalOptions): Validator;
withMessage(message: string): Validator;
notEmpty(): this;
len(options: Options.MinMaxOptions): this;
}

@@ -285,241 +159,5 @@

normalizeEmail(options?: ExpressValidator.Options.NormalizeEmailOptions): Sanitizer;
normalizeEmail(options?: Options.NormalizeEmailOptions): Sanitizer;
}
interface MappedError {
param: string;
msg: string;
value: string;
}
}
declare namespace ExpressValidator.Options {
export interface ExpressValidatorOptions {
customValidators?: { [validatorName: string]: (...value: any[]) => boolean | Promise<any> }
customSanitizers?: { [sanitizername: string]: (value: any) => any }
errorFormatter?: (param?: string, msg?: string, value?: any) => any
}
interface ValidatorSchemaOptions {
options?: any[]
errorMessage?: string
}
interface ValidationSchemaParamOptions {
in?: Location
errorMessage?: string
// Additional ValidatorChain.prototype.* validators
optional?: boolean | { checkFalsy: boolean }
notEmpty?: boolean | { errorMessage: string }
len?: ValidatorSchemaOptions
// exported from validator.js
isEmail?: ValidatorSchemaOptions
isURL?: ValidatorSchemaOptions
isMACAddress?: ValidatorSchemaOptions
isIP?: ValidatorSchemaOptions
isFQDN?: ValidatorSchemaOptions
isBoolean?: ValidatorSchemaOptions
isAlpha?: ValidatorSchemaOptions
isAlphanumeric?: ValidatorSchemaOptions
isNumeric?: ValidatorSchemaOptions
isLowercase?: ValidatorSchemaOptions
isUppercase?: ValidatorSchemaOptions
isAscii?: ValidatorSchemaOptions
isFullWidth?: ValidatorSchemaOptions
isHalfWidth?: ValidatorSchemaOptions
isVariableWidth?: ValidatorSchemaOptions
isMultibyte?: ValidatorSchemaOptions
isSurrogatePair?: ValidatorSchemaOptions
isInt?: ValidatorSchemaOptions
isFloat?: ValidatorSchemaOptions
isDecimal?: ValidatorSchemaOptions
isHexadecimal?: ValidatorSchemaOptions
isDivisibleBy?: ValidatorSchemaOptions
isHexColor?: ValidatorSchemaOptions
isMD5?: ValidatorSchemaOptions
isJSON?: ValidatorSchemaOptions
isEmpty?: ValidatorSchemaOptions
isLength?: ValidatorSchemaOptions
isByteLength?: ValidatorSchemaOptions
isUUID?: ValidatorSchemaOptions
isMongoId?: ValidatorSchemaOptions
isDate?: ValidatorSchemaOptions
isAfter?: ValidatorSchemaOptions
isBefore?: ValidatorSchemaOptions
isIn?: ValidatorSchemaOptions
isCreditCard?: ValidatorSchemaOptions
isISIN?: ValidatorSchemaOptions
isISBN?: ValidatorSchemaOptions
isISSN?: ValidatorSchemaOptions
isMobilePhone?: ValidatorSchemaOptions
isCurrency?: ValidatorSchemaOptions
isISO8601?: ValidatorSchemaOptions
isBase64?: ValidatorSchemaOptions
isDataURI?: ValidatorSchemaOptions
isWhitelisted?: ValidatorSchemaOptions
// Additional Validators provided by validator.js
equals?: ValidatorSchemaOptions
contains?: ValidatorSchemaOptions
matches?: ValidatorSchemaOptions
}
// VALIDATORS
interface MinMaxOptions {
min?: number;
max?: number;
}
interface MinMaxExtendedOptions extends MinMaxOptions {
lt?: number;
gt?: number;
}
interface IsIntOptions extends MinMaxExtendedOptions {
allow_leading_zeroes?: boolean;
}
/**
* defaults to
* {
* allow_display_name: false,
* require_display_name: false,
* allow_utf8_local_part: true,
* require_tld: true
* }
*/
interface IsEmailOptions {
allow_display_name?: boolean;
allow_utf8_local_part?: boolean;
require_tld?: boolean;
}
/**
* defaults to
* {
* protocols: ['http','https','ftp'],
* require_tld: true,
* require_protocol: false,
* require_host: true,
* require_valid_protocol: true,
* allow_underscores: false,
* host_whitelist: false,
* host_blacklist: false,
* allow_trailing_dot: false,
* allow_protocol_relative_urls: false
* }
*/
interface IsURLOptions {
protocols?: URLProtocol[];
require_tld?: boolean;
require_protocol?: boolean;
require_host?: boolean;
require_valid_protocol?: boolean;
allow_underscores?: boolean;
host_whitelist?: (string | RegExp)[];
host_blacklist?: (string | RegExp)[];
allow_trailing_dot?: boolean;
allow_protocol_relative_urls?: boolean;
}
/**
* defaults to
* {
* require_tld: true,
* allow_underscores: false,
* allow_trailing_dot: false
* }
*/
interface IsFQDNOptions {
require_tld?: boolean;
allow_underscores?: boolean;
allow_trailing_dot?: boolean;
}
/**
* defaults to
* {
* case_sensitive: false,
* require_hyphen: false
* }
*/
interface IsISSNOptions {
case_sensitive?: boolean
require_hyphen?: boolean
}
/**
* defaults to
* {
* symbol: '$',
* require_symbol: false,
* allow_space_after_symbol: false,
* symbol_after_digits: false,
* allow_negatives: true,
* parens_for_negatives: false,
* negative_sign_before_digits: false,
* negative_sign_after_digits: false,
* allow_negative_sign_placeholder: false,
* thousands_separator: ',',
* decimal_separator: '.',
* allow_space_after_digits: false
* }
*/
interface IsCurrencyOptions {
symbol?: string;
require_symbol?: boolean;
allow_space_after_symbol?: boolean;
symbol_after_digits?: boolean;
allow_negatives?: boolean;
parens_for_negatives?: boolean;
negative_sign_before_digits?: boolean;
negative_sign_after_digits?: boolean;
allow_negative_sign_placeholder?: boolean;
thousands_separator?: string;
decimal_separator?: string;
allow_space_after_digits?: boolean;
}
interface OptionalOptions {
checkFalsy?: boolean;
}
// SANITIZERS
/**
* Defaults to
* {
* all_lowercase: true
* gmail_lowercase: true
* gmail_remove_dots: true
* gmail_remove_subaddress: true
* gmail_convert_googlemaildotcom: true
* outlookdotcom_lowercase: true
* outlookdotcom_remove_subaddress: true
* yahoo_lowercase: true
* yahoo_remove_subaddress: true
* icloud_lowercase: true
* icloud_remove_subaddress: true
* }
*/
interface NormalizeEmailOptions {
all_lowercase?: boolean
gmail_lowercase?: boolean
gmail_remove_dots?: boolean
gmail_remove_subaddress?: boolean
gmail_convert_googlemaildotcom?: boolean
outlookdotcom_lowercase?: boolean
outlookdotcom_remove_subaddress?: boolean
yahoo_lowercase?: boolean
yahoo_remove_subaddress?: boolean
icloud_lowercase?: boolean
icloud_remove_subaddress?: boolean
}
}
var deprecate = require('util').deprecate;
var validator = require('validator');
var _ = require('lodash');
var Promise = require('bluebird');
var utils = require('./utils');
var check = require('../check/check');
var selectFields = require('../check/select-fields');
var validationResult = require('../check/validation-result');
var validatorChainSymbol = Symbol('express-validator.validatorChain');
var sanitizerSymbol = Symbol('express-validator.sanitizer');
// Because req.validationErrors and req.asyncValidationErrors are build dynamically,

@@ -21,19 +26,2 @@ // these warnings would appear everytime a new request comes in.

/**
* display warnings once per each validator
* which returns null or undefined as a validation
* result
*/
var warnValidatorNilReturn = (function() {
var warned = {};
return function(methodName, returnedValue) {
if (warned[methodName]) {
return;
}
warned[methodName] = true;
console.warn('WARNING: unexpected return value: `' + returnedValue + '` returned by `' + methodName + '` validator');
}
}());
// When validator upgraded to v5, they removed automatic string coercion

@@ -81,5 +69,6 @@ // The next few methods (up to validator.init()) restores that functionality

// validators and sanitizers not prefixed with is/to
var additionalValidators = ['contains', 'equals', 'matches'];
var additionalSanitizers = ['trim', 'ltrim', 'rtrim', 'escape', 'unescape', 'stripLow', 'whitelist', 'blacklist', 'normalizeEmail'];
var allLocations = ['params', 'query', 'body', 'headers', 'cookies'];
/**

@@ -110,24 +99,2 @@ * Adds validation methods to request object via express middleware

/**
* Initializes a chain of validators
*
* @class
* @param {(string|string[])} param path to property to validate
* @param {string} failMsg validation failure message
* @param {Request} req request to attach validation errors
* @param {string} location request property to find value (body, params, query, etc.)
* @param {object} options options containing error formatter
*/
function ValidatorChain(param, failMsg, req, location, options) {
this.errorFormatter = options.errorFormatter;
this.param = param;
this.value = location ? _.get(req[location], param) : undefined;
this.validationErrors = [];
this.failMsg = failMsg;
this.req = req;
this.lastError = null; // used by withMessage to get the values of the last error
return this;
}
/**
* Initializes a sanitizer

@@ -152,2 +119,26 @@ *

function createValidationChain(field, location, message, req, contexts) {
const chain = check([field], Array.isArray(location) ? location : [location], message);
contexts.push(chain._context);
chain.notEmpty = () => chain.isLength({ min: 1 });
chain.len = chain.isLength;
req[validatorChainSymbol].forEach(customValidators => {
Object.keys(customValidators).forEach(name => {
chain[name] = (...options) => {
chain._context.validators.push({
options,
negated: chain._context.negateNext,
validator: customValidators[name]
});
chain._context.negateNext = false;
return chain;
};
});
});
return chain;
}
/**

@@ -178,9 +169,7 @@ * validate an object using a schema, using following format:

* @param {string} loc request property to find value (body, params, query, etc.)
* @param {Object} options options containing custom validators & errorFormatter
* @return {object[]} array of errors
*/
function validateSchema(schema, req, loc, options) {
var locations = ['body', 'params', 'query', 'headers'],
currentLoc = loc;
function validateSchema(schema, req, loc, contexts) {
var currentLoc = loc;

@@ -191,3 +180,3 @@ for (var param in schema) {

if (schema[param].hasOwnProperty('in')) {
if (locations.indexOf(schema[param].in) !== -1) {
if (allLocations.indexOf(schema[param].in) !== -1) {
currentLoc = schema[param].in;

@@ -199,7 +188,7 @@ } else {

} else {
currentLoc = loc === 'any' ? locate(req, param) : currentLoc;
currentLoc = loc === 'any' ? allLocations : currentLoc;
}
var validator = new ValidatorChain(param, null, req, currentLoc, options);
var paramErrorMessage = schema[param].errorMessage;
const paramErrorMessage = schema[param].errorMessage;
var validator = createValidationChain(param, currentLoc, paramErrorMessage, req, contexts);

@@ -210,7 +199,2 @@ var opts;

validator.optional.apply(validator, schema[param].optional.options);
if (validator.skipValidating) {
validator.failMsg = schema[param].optional.errorMessage || paramErrorMessage || 'Invalid param';
continue; // continue with the next param in schema
}
}

@@ -228,13 +212,10 @@

if (methodName === 'errorMessage') {
/* Also do not validate if methodName
* represent parameter error message
*/
if (methodName === 'errorMessage' || !schema[param][methodName]) {
// Also do not validate if methodName represent parameter error message
// or if the value is falsy
continue;
}
validator.failMsg = schema[param][methodName].errorMessage || paramErrorMessage || 'Invalid param';
opts = schema[param][methodName].options || [];
opts = schema[param][methodName].options;
if (opts != null && !Array.isArray(opts)) {

@@ -244,3 +225,5 @@ opts = [opts];

validator[methodName].apply(validator, opts);
validator
[methodName](...opts)
.withMessage(schema[param][methodName].errorMessage);
}

@@ -250,99 +233,72 @@ }

// _.set validators and sanitizers as prototype methods on corresponding chains
// _.set sanitizers as prototype methods on corresponding chains
_.forEach(validator, function(method, methodName) {
if (methodName.match(/^is/) || _.includes(additionalValidators, methodName)) {
ValidatorChain.prototype[methodName] = makeValidator(methodName, validator);
}
if (methodName.match(/^to/) || _.includes(additionalSanitizers, methodName)) {
Sanitizer.prototype[methodName] = makeSanitizer(methodName, validator);
Sanitizer.prototype[methodName] = utils.makeSanitizer(methodName, validator);
}
});
ValidatorChain.prototype.notEmpty = function() {
return this.isLength({
min: 1
});
};
utils.mapAndExtend(options.customSanitizers, Sanitizer.prototype, utils.makeSanitizer);
ValidatorChain.prototype.len = function() {
return this.isLength.apply(this, arguments);
};
return function(req, res, next) {
const contexts = [];
function runContexts() {
contexts.filter(context => !context.promise).forEach(context => {
const field = selectFields(req, context)[0];
if (!field) {
context.promise = Promise.resolve();
return;
}
ValidatorChain.prototype.optional = function(opts) {
opts = opts || {};
// By default, optional checks if the key exists, but the user can pass in
// checkFalsy: true to skip validation if the property is falsy
var defaults = {
checkFalsy: false
};
const promises = context.validators.map(validatorCfg => {
const result = validatorCfg.validator(field.value, ...validatorCfg.options);
const errorObj = options.errorFormatter(
utils.formatParamOutput(field.path),
utils.replaceArgs(
validatorCfg.message || context.message || 'Invalid value',
[field.value, ...validatorCfg.options]
),
field.value
);
var options = _.assign(defaults, opts);
if (result && result.then) {
req._asyncValidationErrors.push(result.then(() => {
validatorCfg.negated && req._validationErrors.push(errorObj);
}, () => {
!validatorCfg.negated && req._validationErrors.push(errorObj);
}));
} else if ((!validatorCfg.negated && !result) || (validatorCfg.negated && result)) {
req._validationErrors.push(errorObj);
}
});
if (options.checkFalsy) {
if (!this.value) {
this.skipValidating = true;
}
} else {
if (this.value === undefined) {
this.skipValidating = true;
}
context.promise = Promise.all(promises);
});
}
return this;
};
var locations = ['body', 'params', 'query', 'cookies'];
ValidatorChain.prototype.withMessage = function(message) {
if (this.lastError) {
if (this.lastError.isAsync) {
this.req._asyncValidationErrors.pop().catch(function() {
// Suppress errors from original promise - they should go to the new one.
// Otherwise bluebird throws an 'unhandled rejection' error
});
var error = formatErrors.call(this.lastError.context, this.lastError.param, message, this.lastError.value);
var promise = this.lastError.promise.catch(function() {
return Promise.reject(error);
});
this.req._asyncValidationErrors.push(promise);
} else {
this.validationErrors.pop();
this.req._validationErrors.pop();
var errorMessage = formatErrors.call(this, this.lastError.param, message, this.lastError.value);
this.validationErrors.push(errorMessage);
this.req._validationErrors.push(errorMessage);
this.lastError = null;
}
// Extend existing validators. Fixes bug #341
req[validatorChainSymbol] = req[validatorChainSymbol] || [];
req[validatorChainSymbol].push(options.customValidators);
// Extend existing sanitizer. Fixes bug #341
if (req[sanitizerSymbol] && req[sanitizerSymbol] !== Sanitizer) {
Sanitizer = req[sanitizerSymbol];
utils.mapAndExtend(options.customSanitizers, Sanitizer.prototype, utils.makeSanitizer);
}
return this;
};
req[sanitizerSymbol] = Sanitizer;
_.forEach(options.customValidators, function(method, customValidatorName) {
ValidatorChain.prototype[customValidatorName] = makeValidator(customValidatorName, options.customValidators);
});
_.forEach(options.customSanitizers, function(method, customSanitizerName) {
Sanitizer.prototype[customSanitizerName] = makeSanitizer(customSanitizerName, options.customSanitizers);
});
return function(req, res, next) {
var locations = ['body', 'params', 'query'];
req._validationErrors = [];
req._asyncValidationErrors = [];
req.validationErrors = function(mapped, promisesResolved) {
req.validationErrors = function(mapped) {
warnValidationErrors();
if (!promisesResolved && req._asyncValidationErrors.length > 0) {
console.warn('WARNING: You have asynchronous validators but you have not used asyncValidateErrors to check for errors.');
}
runContexts();
if (mapped && req._validationErrors.length > 0) {
var errors = {};
req._validationErrors.forEach(function(err) {
errors[err.param] = err;
});
return errors;
var result = validationResult(req);
if (result.isEmpty()) {
return false;
}
return req._validationErrors.length > 0 ? req._validationErrors : false;
return mapped ? result.mapped() : result.array();
};

@@ -352,24 +308,9 @@

warnAsyncValidationErrors();
return new Promise(function(resolve, reject) {
var promises = req._asyncValidationErrors;
// Migrated using the recommended fix from
// http://bluebirdjs.com/docs/api/reflect.html
Promise.all(promises.map(function(promise) {
// Must convert to Bluebird promise in case they are using native
// Node promises since reflect() is not a native promise method
// http://bluebirdjs.com/docs/api/reflect.html#comment-2369616577
return Promise.resolve(promise).reflect();
})).then(function(results) {
runContexts();
return Promise.all(req._asyncValidationErrors).then(() => {
if (req._validationErrors.length > 0) {
return Promise.reject(req.validationErrors(mapped, true));
}
results.forEach(function(result) {
if (result.isRejected()) {
req._validationErrors.push(result.reason());
}
});
if (req._validationErrors.length > 0) {
return reject(req.validationErrors(mapped, true));
}
resolve();
});
return Promise.resolve();
});

@@ -379,20 +320,5 @@ };

req.getValidationResult = function() {
return new Promise(function(resolve) {
var promises = req._asyncValidationErrors;
// Migrated using the recommended fix from
// http://bluebirdjs.com/docs/api/reflect.html
Promise.all(promises.map(function(promise) {
// Must convert to Bluebird promise in case they are using native
// Node promises since reflect() is not a native promise method
// http://bluebirdjs.com/docs/api/reflect.html#comment-2369616577
return Promise.resolve(promise).reflect();
})).then(function(results) {
results.forEach(function(result) {
if (result.isRejected()) {
req._validationErrors.push(result.reason());
}
});
return resolve(utils.decorateAsValidationResult({}, req._validationErrors));
});
runContexts();
return Promise.all(req._asyncValidationErrors).then(() => {
return validationResult(req);
});

@@ -402,17 +328,17 @@ };

locations.forEach(function(location) {
/**
* @name req.sanitizeQuery
* @see sanitize
* @param param
*/
/**
* @name req.sanitizeParams
* @see sanitize
* @param param
*/
/**
* @name req.sanitizeBody
* @see sanitize
* @param param
*/
/**
* @name req.sanitizeQuery
* @see sanitize
* @param param
*/
/**
* @name req.sanitizeParams
* @see sanitize
* @param param
*/
/**
* @name req.sanitizeBody
* @see sanitize
* @param param
*/
req['sanitize' + _.capitalize(location)] = function(param) {

@@ -431,6 +357,2 @@ return new Sanitizer(param, req, [location]);

req.sanitizeCookies = function(param) {
return new Sanitizer(param, req, ['cookies']);
};
req.sanitize = function(param) {

@@ -459,7 +381,13 @@ return new Sanitizer(param, req, locations);

*/
/**
* @name req.checkCookies
* @see check
* @param param
* @param [failMsg]
*/
req['check' + _.capitalize(location)] = function(param, failMsg) {
if (_.isPlainObject(param)) {
return validateSchema(param, req, location, options);
return validateSchema(param, req, location, contexts);
}
return new ValidatorChain(param, failMsg, req, location, options);
return createValidationChain(param, location, failMsg, req, contexts);
};

@@ -470,3 +398,3 @@ });

if (_.isPlainObject(param)) {
return validateSchema(param, req, 'headers', options);
return validateSchema(param, req, 'headers', contexts);
}

@@ -478,14 +406,10 @@

return new ValidatorChain(param.toLowerCase(), failMsg, req, 'headers', options);
return createValidationChain(param.toLowerCase(), 'headers', failMsg, req, contexts);
};
req.checkCookies = function(param, failMsg) {
return new ValidatorChain(param, failMsg, req, 'cookies', options);
};
req.check = function(param, failMsg) {
if (_.isPlainObject(param)) {
return validateSchema(param, req, 'any', options);
return validateSchema(param, req, 'any', contexts);
}
return new ValidatorChain(param, failMsg, req, locate(req, param), options);
return createValidationChain(param, allLocations, failMsg, req, contexts);
};

@@ -501,128 +425,4 @@

/**
* Validates and handles errors, return instance of itself to allow for chaining
*
* @method makeValidator
* @param {string} methodName
* @param {object} container
* @return {function}
*/
function makeValidator(methodName, container) {
return function() {
if (this.skipValidating) {
return this;
}
var args = [];
args.push(this.value);
args = args.concat(Array.prototype.slice.call(arguments));
var isValid = container[methodName].apply(container, args);
// Perform string replacement in the error message
var msg = this.failMsg;
if (typeof msg === 'string') {
args.forEach(function(arg, i) { msg = msg.replace('%' + i, arg); });
}
var error = formatErrors.call(this, this.param, msg || 'Invalid value', this.value);
var isNilValue = isValid === undefined || isValid === null
if (isNilValue) {
warnValidatorNilReturn(methodName, isValid);
}
if (!isNilValue && isValid.then) {
var promise = isValid.catch(function() {
return Promise.reject(error);
});
this.lastError = {
promise: isValid,
param: this.param,
value: this.value,
context: this,
isAsync: true
};
this.req._asyncValidationErrors.push(promise);
} else if (!isValid) {
this.validationErrors.push(error);
this.req._validationErrors.push(error);
this.lastError = { param: this.param, value: this.value, isAsync: false };
} else {
this.lastError = null;
}
return this;
};
}
/**
* Sanitizes and sets sanitized value on the request, then return instance of itself to allow for chaining
*
* @method makeSanitizer
* @param {string} methodName
* @param {object} container
* @return {function}
*/
function makeSanitizer(methodName, container) {
return function() {
var _arguments = arguments;
var result;
this.values.forEach(function(value, i) {
if (value != null) {
var args = [value];
args = args.concat(Array.prototype.slice.call(_arguments));
result = container[methodName].apply(container, args);
_.set(this.req[this.locations[i]], this.param, result);
this.values[i] = result;
}
}.bind(this));
return result;
};
}
/**
* find location of param
*
* @method param
* @param {Request} req express request object
* @param {(string|string[])} name [description]
* @return {string}
*/
function locate(req, name) {
if (_.get(req.params, name)) {
return 'params';
} else if (_.has(req.query, name)) {
return 'query';
} else if (_.has(req.body, name)) {
return 'body';
}
return undefined;
}
/**
* format param output if passed in as array (for nested)
* before calling errorFormatter
*
* @method param
* @param {(string|string[])} param parameter as a string or array
* @param {string} msg
* @param {string} value
* @return {function}
*/
function formatErrors(param, msg, value) {
var formattedParam = utils.formatParamOutput(param);
return this.errorFormatter(formattedParam, msg, value);
}
module.exports = expressValidator;
module.exports.validator = validator;
module.exports.utils = utils;

@@ -0,1 +1,2 @@

var _ = require('lodash');
var validator = require('validator');

@@ -28,43 +29,37 @@

exports.decorateAsValidationResult = function decorateAsValidationResult(obj, errors) {
var onlyFirstError = false;
exports.mapAndExtend = function createCustomValidators(src, dest, mapFunction) {
Object.keys(src).forEach(function (name) {
dest[name] = mapFunction(name, src);
});
};
obj.isEmpty = function isEmpty() {
return !errors.length;
};
exports.replaceArgs = function replaceArgs(msg, args) {
return args.reduce((msg, arg, index) => msg.replace('%' + index, arg), msg);
};
obj.array = function allErrors() {
var used = {};
return !onlyFirstError ? errors : errors.filter(function(error) {
if (used[error.param]) {
return false;
}
/**
* Sanitizes and sets sanitized value on the request, then return instance of itself to allow for chaining
*
* @method makeSanitizer
* @param {string} methodName
* @param {object} container
* @return {function}
*/
exports.makeSanitizer = function makeSanitizer(methodName, container) {
return function() {
var _arguments = arguments;
var result;
this.values.forEach(function(value, i) {
if (value != null) {
var args = [value];
args = args.concat(Array.prototype.slice.call(_arguments));
result = container[methodName].apply(container, args);
used[error.param] = true;
return true;
});
};
obj.mapped = function mappedErrors() {
return errors.reduce(function(mapping, error) {
if (!onlyFirstError || !mapping[error.param]) {
mapping[error.param] = error;
_.set(this.req[this.locations[i]], this.param, result);
this.values[i] = result;
}
}.bind(this));
return mapping;
}, {});
return result;
};
obj.useFirstErrorOnly = function useFirstErrorOnly(flag) {
onlyFirstError = flag === undefined || flag;
return obj;
};
obj.throw = function throwError() {
if (errors.length) {
throw decorateAsValidationResult(new Error('Validation failed'), errors);
}
};
return obj;
};
}

@@ -14,3 +14,3 @@ {

],
"version": "3.2.1",
"version": "4.0.0",
"homepage": "https://github.com/ctavan/express-validator",

@@ -31,21 +31,16 @@ "license": "MIT",

"engines": {
"node": ">= 0.10"
"node": ">= 6.0.0"
},
"dependencies": {
"@types/bluebird": "^3.4.0",
"@types/express": "~4.0.34",
"bluebird": "^3.4.0",
"lodash": "^4.16.0",
"validator": "~6.2.0"
"validator": "~8.1.0"
},
"devDependencies": {
"body-parser": "1.12.3",
"chai": "2.3.0",
"cookie-parser": "1.4.1",
"coveralls": "2.11.14",
"eslint": "^3.13.1",
"eslint": "^4.5.0",
"express": "4.12.3",
"mocha": "2.2.4",
"nyc": "8.4.0",
"supertest": "0.15.0",
"mocha": "^3.5.0",
"nyc": "^11.1.0",
"typescript": "^2.3.4"

@@ -52,0 +47,0 @@ },

@@ -9,21 +9,18 @@ # express-validator

An [express.js]( https://github.com/visionmedia/express ) middleware for
[node-validator]( https://github.com/chriso/validator.js ).
[validator]( https://github.com/chriso/validator.js ).
- [Upgrade notice](#upgrade-notice)
- [Installation](#installation)
- [Usage](#usage)
- [Middleware options](#middleware-options)
- [Validation](#validation)
- [Validation by schema](#validation-by-schema)
- [Validation result](#validation-result)
+ [Result API](#result-api)
+ [Deprecated API](#deprecated-api)
+ [String formatting for error messages](#string-formatting-for-error-messages)
+ [Per-validation messages](#per-validation-messages)
- [Optional input](#optional-input)
- [Sanitizer](#sanitizer)
- [Regex routes](#regex-routes)
- [TypeScript](#typescript)
- [`check` API](#check-api)
- [`filter` API](#filter-api)
- [Validation Chain API](#validation-chain-api)
- [Validation Result API](#validation-result-api)
- [Legacy API](#legacy-api)
- [Changelog](#changelog)
- [License](#license)
## Upgrade notice
If you're arriving here as a express-validator v3 user after upgrading to v4, please check the [upgrade guide](UPGRADE_GUIDE.md) in order to find out what's different!
## Installation

@@ -36,493 +33,389 @@

## Usage
> The version 3 style of doing validations is still available.
> Please check the [legacy API](#legacy-api) for the docs.
```javascript
var util = require('util'),
bodyParser = require('body-parser'),
express = require('express'),
expressValidator = require('express-validator'),
app = express();
const { check, validationResult } = require('express-validator/check');
const { matchedData } = require('express-validator/filter');
app.use(bodyParser.bodyParser({ extended: true }));
app.use(expressValidator([options])); // this line must be immediately after any of the bodyParser middlewares!
app.post('/user', [
check('username')
// Every validator method in the validator lib is available as a
// method in the check() APIs.
// You can customize per validator messages with .withMessage()
.isEmail().withMessage('must be an email')
app.post('/:urlparam', function(req, res) {
// ...or throw your own errors using validators created with .custom()
.custom(value => {
return findUserByEmail(value).then(user => {
throw new Error('this email is already in use');
})
}),
// VALIDATION
// checkBody only checks req.body; none of the other req parameters
// Similarly checkParams only checks in req.params (URL params) and
// checkQuery only checks req.query (GET params).
req.checkBody('postparam', 'Invalid postparam').notEmpty().isInt();
req.checkParams('urlparam', 'Invalid urlparam').isAlpha();
req.checkQuery('getparam', 'Invalid getparam').isInt();
// General error messages can be given as a 2nd argument in the check APIs
check('password', 'passwords must be at least 5 chars long and contain one number')
.isLength({ min: 5 })
.matches(/\d/),
// OR assert can be used to check on all 3 types of params.
// req.assert('postparam', 'Invalid postparam').notEmpty().isInt();
// req.assert('urlparam', 'Invalid urlparam').isAlpha();
// req.assert('getparam', 'Invalid getparam').isInt();
// No special validation required? Just check if data exists:
check('addresses.*.street').exists(),
// SANITIZATION
// as with validation these will only validate the corresponding
// request object
req.sanitizeBody('postparam').toBoolean();
req.sanitizeParams('urlparam').toBoolean();
req.sanitizeQuery('getparam').toBoolean();
// Wildcards * are accepted!
check('addresses.*.postalCode').isPostalCode(),
], (req, res, next) => {
// Get the validation result whenever you want
const errors = validationResult(req).throw();
if (!errors.isEmpty()) {
return res.status(422).json({ errors: err.mapped() });
}
// OR find the relevent param in all areas
req.sanitize('postparam').toBoolean();
// Alternatively use `var result = yield req.getValidationResult();`
// when using generators e.g. with co-express
req.getValidationResult().then(function(result) {
if (!result.isEmpty()) {
res.status(400).send('There have been validation errors: ' + util.inspect(result.array()));
return;
}
res.json({
urlparam: req.params.urlparam,
getparam: req.query.getparam,
postparam: req.body.postparam
});
});
// matchedData returns only the subset of data validated by the middleware
const user = matchedData(req);
createUser(user).then(user => res.json(user));
});
app.listen(8888);
```
Which will result in:
---
```
$ curl -d 'postparam=1' http://localhost:8888/test?getparam=1
{"urlparam":"test","getparam":"1","postparam":true}
## `check` API
These methods are all available via `require('express-validator/check')`.
$ curl -d 'postparam=1' http://localhost:8888/t1est?getparam=1
There have been validation errors: [
{ param: 'urlparam', msg: 'Invalid urlparam', value: 't1est' } ]
### `check(field[, message])`
- `field`: a string or an array of strings of field names to validate against.
- `message` *(optional)*: an error message to use when failed validators don't specify a message. Defaults to `Invalid value`.
> *Returns:* a [Validation Chain](#validation-chain-api)
$ curl -d 'postparam=1' http://localhost:8888/t1est?getparam=1ab
There have been validation errors: [
{ param: 'getparam', msg: 'Invalid getparam', value: '1ab' },
{ param: 'urlparam', msg: 'Invalid urlparam', value: 't1est' } ]
Creates a validation chain for one or more fields. They may be located in any of the following request objects:
- `req.body`
- `req.cookies`
- `req.headers`
- `req.params`
- `req.query`
$ curl http://localhost:8888/test?getparam=1&postparam=1
There have been validation errors: [
{ param: 'postparam', msg: 'Invalid postparam', value: undefined} ]
```
If any of the fields are present in more than one location, then all instances of that field value must pass the validation.
## Middleware Options
#### `errorFormatter`
_function(param,msg,value)_
The validators will always be executed serially for the same field.
This means that if the chain targets more than one field, those will run in parallel, but each of their validators are serial.
The `errorFormatter` option can be used to specify a function that must build the error objects used in the validation result returned by `req.getValidationResult()`.<br>
It should return an `Object` that has `param`, `msg`, and `value` keys defined.
### `body(fields[, message])`
Same as `check(fields[, message])`, but only checking `req.body`.
```javascript
// In this example, the formParam value is going to get morphed into form body format useful for printing.
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
### `cookie(fields[, message])`
Same as `check(fields[, message])`, but only checking `req.cookies`.
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param : formParam,
msg : msg,
value : value
};
}
}));
```
### `header(fields[, message])`
Same as `check(fields[, message])`, but only checking `req.headers`.
#### `customValidators`
_{ "validatorName": function(value, [additional arguments]), ... }_
### `param(fields[, message])`
Same as `check(fields[, message])`, but only checking `req.params`.
### `query(fields[, message])`
Same as `check(fields[, message])`, but only checking `req.query`.
The `customValidators` option can be used to add additional validation methods as needed. This option should be an `Object` defining the validator names and associated validation functions.
### `oneOf(validationChains[, message])`
- `validationChains`: an array of [validation chains](#validation-chain-api) created with `check()` or any of its variations.
- `message` *(optional)*: an error message to use when all chains failed. Defaults to `Invalid value(s)`.
> *Returns:* a middleware instance
Define your custom validators:
Creates a middleware instance that will ensure at least one of the given chains passes the validation.
If none of the given chains passes, an error will be pushed to the `_error` pseudo-field,
using the given `message`, and the errors of each chain will be made available under a key `nestedErrors`.
```javascript
app.use(expressValidator({
customValidators: {
isArray: function(value) {
return Array.isArray(value);
},
gte: function(param, num) {
return param >= num;
}
}
}));
```
Use them with their validator name:
```javascript
req.checkBody('users', 'Users must be an array').isArray();
req.checkQuery('time', 'Time must be an integer great than or equal to 5').isInt().gte(5)
```
#### `customSanitizers`
_{ "sanitizerName": function(value, [additional arguments]), ... }_
Example:
The `customSanitizers` option can be used to add additional sanitizers methods as needed. This option should be an `Object` defining the sanitizer names and associated functions.
```js
const { check, oneOf, validationResult } = require('express-validator/check');
app.post('/start-freelancing', oneOf([
check('programming_language').isIn(['javascript', 'java', 'php']),
check('design_tools').isIn(['photoshop', 'gimp'])
]), (req, res, next) => {
try {
validationResult(req).throw();
Define your custom sanitizers:
```javascript
app.use(expressValidator({
customSanitizers: {
toSanitizeSomehow: function(value) {
var newValue = value;//some operations
return newValue;
},
}
}));
// yay! we're good to start selling our skilled services :)))
res.json(...);
} catch (err) {
// Oh noes. This user doesn't have enough skills for this...
res.status(422).json(...);
}
});
```
Use them with their sanitizer name:
```javascript
req.sanitize('address').toSanitizeSomehow();
```
## Validation
The execution of those validation chains are made in parallel,
while the execution within a chain still respects the rule defined in the [`check()` function](#checkfield-message).
#### req.check();
```javascript
req.check('testparam', 'Error Message').notEmpty().isInt();
req.check('testparam.child', 'Error Message').isInt(); // find nested params
req.check(['testparam', 'child'], 'Error Message').isInt(); // find nested params
```
### `validationResult(req)`
- `req`: the express request object.
> *Returns:* a [validation result](#validation-result-api) object
Starts the validation of the specifed parameter, will look for the parameter in `req` in the order `params`, `query`, `body`, then validate, you can use 'dot-notation' or an array to access nested values.
Extracts the validation errors from a request and makes it available in the form of a validation result object.
If a validator takes in params, you would call it like `req.assert('reqParam').contains('thisString');`.
---
Validators are appended and can be chained. See [chriso/validator.js](https://github.com/chriso/validator.js) for available validators, or [add your own](#customvalidators).
## `filter` API
These methods are all available via `require('express-validator/filter')`.
#### req.assert();
Alias for [req.check()](#reqcheck).
### `matchedData(req[, options])`
- `req`: the express request object.
- `options` *(optional)*: an object of options. Defaults to `{ onlyValidData: true }`
> *Returns:* an object of data validated by the `check` APIs.
#### req.validate();
Alias for [req.check()](#reqcheck).
Extracts data validated by the `check` APIs from the request and builds
an object with them. Nested paths and wildcards are properly handled as well.
#### req.checkBody();
Same as [req.check()](#reqcheck), but only looks in `req.body`.
By default, only valid data is included; this means if a field didn't pass
its validation, it won't be included in the returned object.
You can include invalid data by passing the option `onlyValidData` as `false`.
#### req.checkQuery();
Same as [req.check()](#reqcheck), but only looks in `req.query`.
---
#### req.checkParams();
Same as [req.check()](#reqcheck), but only looks in `req.params`.
## Validation Chain API
Any of the validation methods listed by [validator.js](https://github.com/chriso/validator.js) are made available in all validation chains created by express-validator, as long as we're supporting the most up-to-date validator version.
#### req.checkHeaders();
Only checks `req.headers`. This method is not covered by the general `req.check()`.
Additionally, the following methods are also available:
#### req.checkCookies();
Only checks `req.cookies`. This method is not covered by the general `req.check()`.
### `.custom(validator)`
- `validator(value, { req, location, path })`: the custom validator function.
Receives the value of the field being validated, as well as the express request, the location and the field path.
> *Returns:* the current validation chain instance
## Validation by Schema
Adds a custom validator to the current validation chain.
The custom validator may return a promise to indicate an async validation task. In case it's rejected, the field is considered invalid.
Alternatively you can define all your validations at once using a simple schema.
Schema validation will be used if you pass an object to any of the validator methods.
The custom validator may also throw JavaScript exceptions (eg `throw new Error()`) and return falsy values to indicate the field is invalid.
You may pass per-validator error messages with the `errorMessage` key.
Validator options may be passed via `options` key as an array when various values are needed,
or as a single non-null value otherwise.
### `.exists()`
> *Returns:* the current validation chain instance
```javascript
req.checkBody({
'email': {
optional: {
options: { checkFalsy: true } // or: [{ checkFalsy: true }]
},
isEmail: {
errorMessage: 'Invalid Email'
}
},
'password': {
notEmpty: true,
matches: {
options: ['example', 'i'] // pass options to the validator with the options property as an array
// options: [/example/i] // matches also accepts the full expression in the first parameter
},
errorMessage: 'Invalid Password' // Error message for the parameter
},
'name.first': { //
optional: true, // won't validate if field is empty
isLength: {
options: [{ min: 2, max: 10 }],
errorMessage: 'Must be between 2 and 10 chars long' // Error message for the validator, takes precedent over parameter message
},
errorMessage: 'Invalid First Name'
}
});
```
Adds a validator to check for the existence of the current fields in the request.
This means the value of the fields may not be `undefined`; any other values are acceptable.
You can also define a specific location to validate against in the schema by adding `in` parameter as shown below:
### `.not()`
> *Returns:* the current validation chain instance
```javascript
req.check({
'email': {
in: 'query',
notEmpty: true,
isEmail: {
errorMessage: 'Invalid Email'
}
}
});
```
Negates the result of the next validator.
Please remember that the `in` attribute will have always highest priority. This mean if you use `in: 'query'` then checkQuery() will be called inside even if you do `checkParams()` or `checkBody()`. For example, all of these calls will check query params for email param:
```javascript
var schema = {
'email': {
in: 'query',
notEmpty: true,
isEmail: {
errorMessage: 'Invalid Email'
}
},
'password': {
notEmpty: true,
matches: {
options: ['example', 'i'] // pass options to the validator with the options property as an array
// options: [/example/i] // matches also accepts the full expression in the first parameter
},
errorMessage: 'Invalid Password' // Error message for the parameter
}
};
req.check(schema); // will check 'password' no matter where it is but 'email' in query params
req.checkQuery(schema); // will check 'password' and 'email' in query params
req.checkBody(schema); // will check 'password' in body but 'email' in query params
req.checkParams(schema); // will check 'password' in path params but 'email' in query params
req.checkHeaders(schema); // will check 'password' in headers but 'email' in query params
```js
check('weekday').not().isIn(['sunday', 'saturday'])
```
Currently supported location are `'body', 'params', 'query', 'headers'`. If you provide a location parameter that is not supported, the validation process for current parameter will be skipped.
### `.optional(options)`
- `options` *(optional)*: an object of options to customize the optionality behaviour. Defaults to `{ checkFalsy: false }`.
> *Returns:* the current validation chain instance
## Validation result
Marks the current validation chain as optional.
This is useful to remove values that are not essential to your busines and that would cause validation failures in case they were not provided in the request.
### Result API
The method `req.getValidationResult()` returns a Promise which resolves to a result object.
By default, this means fields with `undefined` values will be completely ignored.
However, if you specify the option `{ checkFalsy: true }`, then falsy values (eg `""`, `0`, `false`, `null`) will also be ignored.
```js
req.assert('email', 'required').notEmpty();
req.assert('email', 'valid email required').isEmail();
req.assert('password', '6 to 20 characters required').len(6, 20);
### `.withMessage(message)`
- `message`: the error message to use for the previous validator
> *Returns:* the current validation chain instance
req.getValidationResult().then(function(result) {
// do something with the validation result
});
```
Sets the error message for the previous validator.
This will have precedence over errors thrown by a custom validator.
The API for the result object is the following:
---
#### `result.isEmpty()`
Returns a boolean determining whether there were errors or not.
## Validation Result API
This is an unified API for dealing with errors, both in legacy and check APIs.
#### `result.useFirstErrorOnly()`
Sets the `firstErrorOnly` flag of this result object, which modifies the way
other methods like `result.array()` and `result.mapped()` work.<br>
Each error returned by `.array()` and `.mapped()` methods have the following format:
This method is chainable, so the following is OK:
```js
{
"msg": "The error message",
"param": "param.name.with.index[0]",
"value": "param value",
// Location of the param that generated this error.
// It's either body, query, params, cookies or headers.
"location": "body",
```js
result.useFirstErrorOnly().array();
// nestedErrors only exist when using the oneOf function
"nestedErrors": [{ ... }]
}
```
#### `result.array()`
Returns an array of errors.<br>
All errors for all validated parameters will be included, unless you specify that you want only the first error of each param by invoking `result.useFirstErrorOnly()`.
### `.isEmpty()`
> *Returns:* a boolean indicating whether this result object contains no errors at all.
```javascript
var errors = result.array();
### `.array([options])`
- `options` *(optional)*: an object of options. Defaults to `{ onlyFirstError: false }`
> *Returns:* an array of validation errors.
// errors will now contain something like this:
[
{param: "email", msg: "required", value: "<received input>"},
{param: "email", msg: "valid email required", value: "<received input>"},
{param: "password", msg: "6 to 20 characters required", value: "<received input>"}
]
```
Gets all validation errors contained in this result object.
#### `result.mapped()`
Returns an object of errors, where the key is the parameter name, and the value is an error object as returned by the error formatter.
If the option `onlyFirstError` is set to `true`, then only the first
error for each field will be included.
Because of historical reasons, by default this method will return the last error of each parameter.<br>
You can change this behavior by invoking `result.useFirstErrorOnly()`, so the first error is returned instead.
### `.mapped()`
> *Returns:* an object where the keys are the field names, and the values are the validation errors
```javascript
var errors = result.mapped();
Gets the first validation error of each failed field in the form of an object.
// errors will now be similar to this:
{
email: {
param: "email",
msg: "valid email required",
value: "<received input>"
},
password: {
param: "password",
msg: "6 to 20 characters required",
value: "<received input>"
}
}
```
### `.throw()`
If this result object has errors, then this method will throw an exception
decorated with the same validation result API.
#### `result.throw()`
If there are errors, throws an `Error` object which is decorated with the same API as the validation result object.<br>
Useful for dealing with the validation errors in the `catch` block of a `try..catch` or promise.
```js
try {
result.throw();
res.send('success!');
} catch (e) {
console.log(e.array());
res.send('oops, validation failed!');
validationResult(req).throw();
// Oh look at ma' success! All validations passed!
} catch (err) {
console.log(err.mapped()); // Oh noes!
}
```
### Deprecated API
The following methods are deprecated.<br>
While they work, their API is unflexible and sometimes return weird results if compared to the bleeding edge `req.getValidationResult()`.
---
Additionally, these methods may be removed in a future version.
## Legacy API
The "legacy API" is the same API used by version 3 and older releases of express-validator.
#### `req.validationErrors([mapped])`
Returns synchronous errors in the form of an array, or an object that maps parameter to error in case `mapped` is passed as `true`.<br>
If there are no errors, the returned value is `false`.
It's based around setting a global middleware in your express app and decorating the request object with new methods.
```js
var errors = req.validationErrors();
if (errors) {
// do something with the errors
}
```
> This API **MUST NOT** be used by new apps, since it may not receive new updates and can even be removed in a future major version.
#### `req.asyncValidationErrors([mapped])`
Returns a promise that will either resolve if no validation errors happened, or reject with an errors array/mapping object. For reference on this, see `req.validationErrors()`.
### Setup
You must mount the middleware in your app before you get access to the validation/sanitization methods:
```js
req.asyncValidationErrors().then(function() {
// all good here
}, function(errors) {
// damn, validation errors!
});
const expressValidator = require('express-validator');
app.use(expressValidator(middlewareOptions));
```
### String formatting for error messages
### Middleware options
- `errorFormatter (param, msg, value)`: a function that formats the error objects before returning them to your route handlers.
- `customValidators`: an object where you can specify custom validators.
The key will be the name of the validator, while the value is the validation function, receiving the value and any option.
- `customSanitizers`: an object where you can specify custom sanitizers.
The key will be the name of the sanitizer, while the value is the sanitization function, receiving the value and any option.
Error messages can be customized to include both the value provided by the user, as well as the value of any parameters passed to the validation function, using a standard string replacement format:
### Legacy Validation Chain
The Legacy Validation Chain instances provides further functionality than the one provided by the base [Validation Chain](#validation-chain-api) objects.
It also differs in that the legacy one is not a middleware *per se*.
`%0` is replaced with user input
`%1` is replaced with the first parameter to the validator
`%2` is replaced with the second parameter to the validator
etc...
Any custom validator specified in the middleware will be made available
in instances of this validation chain.
Example:
```javascript
req.assert('number', '%0 is not an integer').isInt();
req.assert('number', '%0 is not divisible by %1').isDivisibleBy(5);
```
Additionally, the following validators are also available:
*Note:* string replacement does **not** work with the `.withMessage()` syntax. If you'd like to have per-validator error messages with string formatting, please use the [Validation by Schema](#validation-by-schema) method instead.
- `.notEmpty()`: alias of `.isLength({ min: 1 })`
- `.len()`: alias of `.isLength()`
### Per-validation messages
### `req.check(field[, message])`
- `field`: the name of a single field to validate against.
- `message` *(optional)*: an error message to use when failed validators don't specify a message. Defaults to `Invalid value`.
> *Returns:* a [legacy validation chain](#legacy-validation-chain)
You can provide an error message for a single validation with `.withMessage()`. This can be chained with the rest of your validation, and if you don't use it for one of the validations then it will fall back to the default.
Creates a validation chain for one field. It may be located in any of the following request objects:
- `req.params`
- `req.query`
- `req.body`
- `req.headers`
- `req.cookies`
```javascript
req.assert('email', 'Invalid email')
.notEmpty().withMessage('Email is required')
.isEmail();
If it's present in more than one location, then only the first one (following the above order) will be validated against.
req.getValidationResult()
.then(function(result){
console.log(result.array());
});
> This function is also aliased as `req.assert()` and `req.validate()`.
```
### `req.checkBody(field[, message])`
Same as `req.check(field[, message])`, but only checking `req.body`.
prints:
### `req.checkCookies(field[, message])`
Same as `req.check(field[, message])`, but only checking `req.cookies`.
```javascript
[
{param: 'email', msg: 'Email is required', value: '<received input>'}
{param: 'email', msg: 'Invalid Email', value: '<received input>'}
]
```
### `req.checkHeaders(field[, message])`
Same as `req.check(field[, message])`, but only checking `req.headers`.
## Optional input
### `req.checkParams(field[, message])`
Same as `req.check(field[, message])`, but only checking `req.params`.
You can use the `optional()` method to skip validation. By default, it only skips validation if the key does not exist on the request object. If you want to skip validation based on the property being falsy (null, undefined, etc), you can pass in `{ checkFalsy: true }`.
### `req.checkQuery(field[, message])`
Same as `req.check(field[, message])`, but only checking `req.query`.
```javascript
req.checkBody('email').optional().isEmail();
//if there is no error, req.body.email is either undefined or a valid mail.
```
### `req.sanitize(field)`
> *Returns:* a sanitizer chain
## Sanitizer
Creates a sanitizer chain that, when any of the sanitization methods is used, the return value is the sanitized value.
Also, the parameter is sanitized in-place; that is, in the below example,
`req.body.comment` will be updated to the sanitized value.
#### req.sanitize();
```javascript
```js
const comment = req.sanitize('comment').trim();
console.log(comment === req.body.comment);
```
req.body.comment = 'a <span>comment</span>';
req.body.username = ' a user ';
If the sanitized parameter is present in more than one location (eg `req.query.comment` and `req.body.comment`), the will all be sanitized.
req.sanitize('comment').escape(); // returns 'a &lt;span&gt;comment&lt;/span&gt;'
req.sanitize('username').trim(); // returns 'a user'
> This function is also aliased as `req.filter()`.
console.log(req.body.comment); // 'a &lt;span&gt;comment&lt;/span&gt;'
console.log(req.body.username); // 'a user'
### `req.sanitizeBody(field[, message])`
Same as `req.sanitize(field[, message])`, but only sanitizing `req.body`.
```
### `req.sanitizeCookies(field[, message])`
Same as `req.sanitize(field[, message])`, but only sanitizing `req.cookies`.
Sanitizes the specified parameter (using 'dot-notation' or array), the parameter will be updated to the sanitized result. Cannot be chained, and will return the result. See [chriso/validator.js](https://github.com/chriso/validator.js) for available sanitizers, or [add your own](#customsanitizers).
### `req.sanitizeHeaders(field[, message])`
Same as `req.sanitize(field[, message])`, but only sanitizing `req.headers`.
If a sanitizer takes in params, you would call it like `req.sanitize('reqParam').whitelist(['a', 'b', 'c']);`.
### `req.sanitizeParams(field[, message])`
Same as `req.sanitize(field[, message])`, but only sanitizing `req.params`.
If the parameter is present in multiple places with the same name e.g. `req.params.comment` & `req.query.comment`, they will all be sanitized.
### `req.sanitizeQuery(field[, message])`
Same as `req.sanitize(field[, message])`, but only sanitizing `req.query`.
#### req.filter();
Alias for [req.sanitize()](#reqsanitize).
### `req.getValidationResult()`
> *Returns:* a promise for a [Validation Result](#validation-result-api) object
#### req.sanitizeBody();
Same as [req.sanitize()](#reqsanitize), but only looks in `req.body`.
Runs all validations and returns a validation result object for the errors gathered, for both sync and async validators.
#### req.sanitizeQuery();
Same as [req.sanitize()](#reqsanitize), but only looks in `req.query`.
### `req.asyncValidationErrors([mapped])`
- `mapped` *(optional)*: whether the result must be an object instead of an array. Defaults to `false`.
> *Returns:* `false` if no errors happened, an array of errors or an object of errors (in case `mapped` argument is `true`).
#### req.sanitizeParams();
Same as [req.sanitize()](#reqsanitize), but only looks in `req.params`.
Runs all validations and returns the errors gathered for all of them.
#### req.sanitizeHeaders();
Only sanitizes `req.headers`. This method is not covered by the general `req.sanitize()`.
### `req.validationErrors([mapped])`
- `mapped` *(optional)*: whether the result must be an object instead of an array. Defaults to `false`.
> *Returns:* `false` if no errors happened, an array of errors or an object of errors (in case `mapped` argument is `true`).
#### req.sanitizeCookies();
Only sanitizes `req.cookies`. This method is not covered by the general `req.sanitize()`.
Runs all validations and returns the errors gathered *only* for the completed validators.
This probably means any async validator will not be completed by the time this method responds.
## Regex routes
### Schema validation
All `req.check` methods can do schema validation. This is a special way of validating data were you pass an object of your expected schema, and all the validations you want:
Express allows you to define regex routes like:
```javascript
app.get(/\/test(\d+)/, function() {});
```js
req.checkBody({
email: {
notEmpty: true,
isEmail: true
},
password: {
notEmpty: true,
matches: {
// more than one options must be passed as arrays
options: ['someregex', 'i'],
// single options may be passed directly
// options: /someregex/i
},
errorMessage: 'Invalid password'
},
// Wildcards and nested paths are supported as well
'name.first': {
optional: {
options: { checkFalsy: true }
}
},
termsAndConditionsAgreement: {
isBoolean: {
errorMessage: 'should be a boolean'
}
}
});
```
You can validate the extracted matches like this:
---
```javascript
req.assert(0, 'Not a three-digit integer.').len(3, 3).isInt();
```
## TypeScript
If you have been using this library with [TypeScript](http://www.typescriptlang.org/),
you must have been using the type definitions from [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e2af6d0/express-validator/express-validator.d.ts).
However, as of v3.1.0, the type definitions are shipped with the library.
So please uninstall the typings from DT. Otherwise they may cause conflicts
## Changelog

@@ -534,2 +427,2 @@

Copyright (c) 2010 Chris O'Hara <cohara87@gmail.com>, MIT License
MIT License

@@ -17,4 +17,7 @@ {

},
"files": [ "index.d.ts", "./test/type-definition.spec.ts" ],
"include": [
"**/*.d.ts",
"**/*.spec.ts"
],
"exclude": [ "node_modules", "coverage" ]
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc