json-input-validator
v0.1.3
Published
node.js module to clean and validate JSON input.
Downloads
5
Readme
json-input-validator
json-input-validator is a node module to validate and clean JSON input.
There are many basic functions to test types and string formats,
but the main function, checkInput()
can be used to validate and clean a JSON object
based on field definitions you specify.
It is useful for validating JSON submitted via AJAX or submitted to an API and, when used appropriately,
can prevent injection attacks.
Given a JSON object, json-input-validator will return a new object that only contains the fields that were defined and only if the field values successfully passed the specified tests. The returned value for each field is converted to the appropriate type, if possible, and is cleaned up based on the specified actions. The end result is that the output can be safely passed on to the rest of the program without fear of missing, invalid, or dangerous values.
Install the module with: npm install json-input-validator
Contents
Basic Functions - type, isNumber, isString, isRegexp, isFunction, isArray, isObject, isArrayWithContent, isObjectWithContent, isDate, isNothing, isSomething, isEmpty, isNegativeNumber, isInteger, isPositiveInteger, isNegativeInteger, isDomain, isHostname, isEmail, parseHttpURL, isHttpURL, parseARN, isARN, isSesARN, stripObject, stripArray
Quick examples
var validator = require('json-input-validator');
Define the input fields:
var fields = [
{
name: 'email_address',
type: 'string',
format: 'email',
require: 'value',
actions: ['strip', 'lowercase']
}, {
name: 'password',
type: 'string',
require: 'value'
}, {
name: 'password2',
type: 'string',
require: 'same as password'
}, {
name: 'remember_me',
type: 'boolean'
}
];
Acceptable input from a user: (This would not normally be defined in the code. It would come from a user submission.)
var input = {
email_address: '[email protected] ',
password: 'abc123',
password2: 'abc123',
remember_me: 1,
extra_field: 'qwerty'
};
Call checkInput():
var output = validator.checkInput(input, fields);
The results:
data
contains the fields that passed the test with cleaned up values. In this case, email_address
was cleaned up and extra_field
was not included because it isn't in the field definitions.
isModified
is true if any of the values were modified through type conversion or actions.
output = {
data: {
email_address: '[email protected]',
password: 'abc123',
password2: 'abc123',
remember_me: true
},
errors: {},
messages: [],
isModified: true
};
More input from a user, but with some problems:
var moreInput = {
email_address: 'test_username',
password: 'abc123',
password2: 'abc12'
};
The function that does the work: (again)
var output = validator.checkInput(moreInput, fields);
The results:
data
only includes the fields that passed their tests. In this case, only the password
field didn't fail.
error
provides the kind of error that occurred per field, making it easy for the script to act appropriately or produce an error message.
messages
provides a list of error messages in English if you want to be lazy and not write your own.
output = {
data: {
password: 'abc123'
},
error: {
email_address: 'format',
password2: 'require'
},
messages: [
'\'email_address\' is the wrong format',
'\'password2\' is not the same as \'password\''
],
isModified: false
};
Basic Functions
While there are many comprehensive modules that determine value types, these functions are included to provide consistency for the checkInput() function regardless of what other modules are available.
type(arg)
Returns the type of the submitted argument, arg
, as a string.
Possible return values are: 'null', 'nan', 'undefined', 'boolean', 'number', 'string', 'regexp', 'symbol', 'array', 'object', 'function'
isNumber(arg)
Returns true
if arg
is a number. false
is returned otherwise.
isNumber(0) // returns true
isNumber(1) // returns true
isNumber(-1.1) // returns true
isNumber(true) // returns false
isNumber('a') // returns false
isString(arg)
Returns true
if arg
is a string. false
is returned otherwise.
isString('a') // returns true
isString('') // returns true
isString(true) // returns false
isString(1) // returns false
isRegexp(arg)
Returns true
if arg
is a regular expression. false
is returned otherwise.
isRegexp(/a+/i) // returns true
isRegexp(new RegExp('a+', 'i')) // returns true
isRegexp(new RegExp(/a+/)) // returns true
isRegexp('a+') // returns false
isRegexp(1) // returns false
isFunction(arg)
Returns true
if arg
is a function. false
is returned otherwise.
isFunction(function() { }) // returns true
isFunction({}) // returns false
isFunction('function() { }') // returns false
isArray(arg)
Returns true
if arg
is an array. false
is returned otherwise.
isArray([1, 2]) // returns true
isArray([]) // returns true
isArray(1) // returns false
isArray(undefined) // returns false
isObject(arg)
Returns true
if arg
is an object. false
is returned otherwise.
isObject({ 'a': 1 }) // returns true
isObject({}) // returns true
isObject(1) // returns false
isObject(undefined) // returns false
isArrayWithContent(arg)
Returns true
if arg
is an array with one or more elements. false
is returned otherwise.
isArrayWithContent([1, 2]) // returns true
isArrayWithContent([0]) // returns true
isArrayWithContent(['']) // returns true
isArrayWithContent([]) // returns false
isArrayWithContent('a') // returns false
isObjectWithContent(arg)
Returns true
if arg
is an object with one or more keys. false
is returned otherwise.
isObjectWithContent({ 'a': 1 }) // returns true
isObjectWithContent({'a':''}) // returns true
isObjectWithContent({}) // returns false
isObjectWithContent('a') // returns false
isDate(arg)
Returns true
if arg
is a date/time object. false
is returned otherwise.
isNothing(arg)
Returns true
if arg
is null, undefined, or NaN. false
is returned otherwise.
isNothing(null) // returns true
isNothing(undefined) // returns true
isNothing(NaN) // returns true
isNothing(false) // returns false
isNothing(0) // returns false
isNothing('') // returns false
isNothing([]) // returns false
isNothing({}) // returns false
isSomething(arg)
Returns true
if arg
is not null, undefined, or NaN. false
is returned otherwise.
isSomething(null) // returns false
isSomething(undefined) // returns false
isSomething(NaN) // returns false
isSomething(false) // returns true
isSomething(0) // returns true
isSomething('') // returns true
isSomething([]) // returns true
isSomething({}) // returns true
isEmpty(arg)
Returns true
if arg
is null, undefined, NaN, false, 0, a blank string, an empty array, or an empty object. false
is returned otherwise.
isEmpty(null) // returns true
isEmpty(undefined) // returns true
isEmpty(NaN) // returns true
isEmpty(false) // returns true
isEmpty(0) // returns true
isEmpty('') // returns true
isEmpty([]) // returns true
isEmpty({}) // returns true
isEmpty(true) // returns false
isEmpty(1) // returns false
isEmpty('a') // returns false
isEmpty([1]) // returns false
isEmpty({'a':1}) // returns false
isNegativeNumber(arg)
Returns true
if arg
is a negative number. false
is returned otherwise.
isNegativeNumber(-2) // returns true
isNegativeNumber(0) // returns true
isNegativeNumber(-1.1) // returns true
isNegativeNumber(1) // returns false (not negative)
isNegativeNumber('1') // returns false (not of type number)
isInteger(arg)
Returns true
if arg
is an integer. false
is returned otherwise.
isInteger(2) // returns true
isInteger(0) // returns true
isInteger(-1) // returns true
isInteger(1.1) // returns false (not an integer)
isInteger('1') // returns false (not of type number)
isPositiveInteger(arg)
Returns true
if arg
is a positive integer. false
is returned otherwise.
isPositiveInteger(2) // returns true
isPositiveInteger(0) // returns true
isPositiveInteger(1.1) // returns false (not an integer)
isPositiveInteger(-1) // returns false (not positive)
isPositiveInteger('1') // returns false (not of type number)
isNegativeInteger(arg)
Returns true
if arg
is a negative integer. false
is returned otherwise.
isNegativeInteger(-2) // returns true
isNegativeInteger(0) // returns true
isNegativeInteger(-1.1) // returns false (not an integer)
isNegativeInteger(1) // returns false (not negative)
isNegativeInteger('-1') // returns false (not of type number)
isDomain(arg)
Returns true
if arg
is a valid second-level + top-level domain name, like 'example.com'. false
is returned otherwise. Use isHostname
if you will encounter domains of more than two levels. The top-level domain is matched against a list of possible top-level domains as of 2015-10-08. Top-level domains released after that time will not match.
isDomain('example.com') // returns true
isDomain('a.ca') // returns true
isDomain('example.co.uk') // returns false
isDomain('www.example.com') // returns false
isDomain('[email protected]') // returns false
isHostname(arg)
Returns true
if arg
is a valid hostname. false
is returned otherwise. This uses isDomain
to validate the top-level domain. See isDomain
for more details.
isHostname('example.com') // returns true
isHostname('a.ca') // returns true
isHostname('www.example.com') // returns true
isHostname('www.dev.example.com') // returns true
isHostname('[email protected]') // returns false
isHostname('http://www.example.com') // returns false
isEmail(arg)
Returns true
if arg
is a valid email address. false
is returned otherwise. This uses isDomain
to validate the top-level domain in the email address. See isDomain
for more details.
isEmail('[email protected]') // returns true
isEmail('[email protected]') // returns true
isEmail('a.b%[email protected]') // returns true
isEmail('example.com') // returns false
isEmail('mailto:[email protected]') // returns false
parseHttpURL(arg)
Returns an object containing the components of the URL passed in arg
. Components include: protocol, hostname, port, path, and queryString. This uses isDomain
to validate the top-level domain. See isDomain
for more details.
var urlComponents = validator.parseHttpURL('http://www.example.com');
// urlComponents = {
// protocol: 'http',
// hostname: 'www.example.com'
// }
var urlComponents = validator.parseHttpURL('https://www.example.com:443/test/sample.php?key=value');
// urlComponents = {
// protocol: 'https',
// hostname: 'www.example.com',
// port: '443',
// path: '/test/sample.php',
// queryString: 'key=value'
// }
isHttpURL(arg)
Returns true
if arg
is a valid email address. false
is returned otherwise. This uses isDomain
to validate the top-level domain. See isDomain
for more details.
isHttpURL('http://example.com') // returns true
isHttpURL('https://www.example.com') // returns true
isHttpURL('http://example.com:80') // returns true
isHttpURL('http://example.com/test') // returns true
isHttpURL('http://example.com?test') // returns true
isHttpURL('www.example.com') // returns false
isHttpURL('[email protected]') // returns false
parseARN(arg)
Returns an object containing the components of the Amazon Resource Name (ARN) passed in arg
. Components include: partition, service, region, accountId, and resource.
var arnComponents = validator.parseARN('arn:aws:ec2:::instance/*');
// arnComponents = {
// partition: 'aws',
// service: 'ec2',
// resource: 'instance/*'
// }
var arnComponents = validator.parseARN('arn:aws:ec2:us-west-2:1234567890:instance/i-1234567');
// arnComponents = {
// partition: 'aws',
// service: 'ec2',
// region: 'us-west-2',
// accountId: '1234567890',
// resource: 'instance/i-1234567'
// }
var arnComponents = validator.parseARN('arn:aws:ses:us-west-2:1234567890:identity/[email protected]');
// arnComponents = {
// partition: 'aws',
// service: 'ses',
// region: 'us-west-2',
// accountId: '1234567890',
// resource: 'identity/[email protected]'
// }
isARN(arg)
Returns true
if arg
is a valid Amazon Resource Name (ARN). false
is returned otherwise.
isARN('arn:aws:ec2:::instance/*')
// returns true
isARN('arn:aws:ec2:us-west-2:1234567890:instance/i-1234567')
// returns true
isARN('arn:aws:ses:us-west-2:1234567890:identity/[email protected]')
// returns true
isSesARN(arg)
Returns true
if arg
is a valid Simple Email Service (SES) Amazon Resource Name (ARN). false
is returned otherwise.
isSesARN('arn:aws:ses:us-west-2:1234567890:identity/example.com')
// returns true
isSesARN('arn:aws:ses:us-west-2:1234567890:identity/[email protected]')
// returns true
isSesARN('arn:aws:ec2:::instance/*')
// returns false
isSesARN('arn:aws:ec2:us-west-2:1234567890:instance/i-1234567')
// returns false
stripObject(source, isEmpty), stripArray(source, isEmpty)
stripObject
and stripArray
modifies the given object or array, source
, by recursively removing key/value pairs
or array elements with values that are null, undefined, empty objects, or empty arrays.
Returns true
if anything was removed. false
, otherwise.
Pass a second argument of true
to also remove values that are false, 0, or ''.
The two functions are identical and both can take arrays and objects as input.
An example of using stripObject
on an object. The key names are not relevant.
var sample = {
'null': null,
'nan': NaN,
'undefined': undefined,
'boolFalse': false,
'boolTrue': true,
'numZero': 0,
'intPositive': 1,
'stringBlank': '',
'stringShort': 'a',
'arrayEmpty': [],
'arrayShort': [1],
'arrayLong': [ 1, [], {}, [1], { b: 2 } ],
'objectEmpty': {},
'objectShort': { a: 1 },
'objectLong': { a: 1, b: [], c: {}, d: [1], e: { f: 2 } }
};
validator.stripObject(sample);
After stripObject
, sample contains the following:
// sample = {
// 'boolFalse': false,
// 'boolTrue': true,
// 'numZero': 0,
// 'intPositive': 1,
// 'stringBlank': '',
// 'stringShort': 'a',
// 'arrayShort': [1],
// 'arrayLong': [ 1, [1], { b: 2 } ],
// 'objectShort': { a: 1 },
// 'objectLong': { a: 1, d: [1], e: { f: 2 } }
// }
An example using the second argument to also strip false, 0, or ''. The key names are not relevant.
var sample2 = {
'null': null,
'nan': NaN,
'undefined': undefined,
'boolFalse': false,
'boolTrue': true,
'numZero': 0,
'intPositive': 1,
'stringBlank': '',
'stringShort': 'a'
};
validator.stripObject(sample2, true);
After stripObject
, sample2 contains the following:
// sample2 = {
// 'boolTrue': true,
// 'intPositive': 1,
// 'stringShort': 'a'
// }
An example of using stripArray
on an array.
var sample = [
null,
NaN,
undefined,
false,
true,
0,
1,
'',
'a',
[],
[1],
[ 1, [], {}, [1], { b: 2 } ],
{},
{ a: 1 },
{ a: 1, b: [], c: {}, d: [1], e: { f: 2 } }
];
validator.stripArray(sample);
After stripArray
, sample contains the following:
// sample = [
// false,
// true,
// 0,
// 1,
// '',
// 'a',
// [1],
// [ 1, [1], { b: 2 } ],
// { a: 1 },
// { a: 1, d: [1], e: { f: 2 } }
// ]
checkInput(data, fields)
checkInput
tests an input object and returns a converted version of the object and errors for any values that do not match the field definitions.
Arguments
data
- An object to be checked, usually user-entered data sent as JSON via an API call.fields
- An array of objects. Each object describes a field that should be allowed in thedata
object.
The field definition object can contain the following entries:
name
(String) - The name, or key, for this field in the input object. This is required.type
(String) - The Javascript type of this field's value used to convert the incoming value or produce error. It should be a string of 'boolean', 'number', 'string', 'array', 'object'. For example, iftype
is set to 'string', but the incoming value is a number, the number is converted to a string or iftype
is set to 'boolean' and the incoming value is a non-blank string or a non-zero number, the value is converted to a boolean set totrue
. If a reasonable conversion can't happen, an error is produced.require
(Boolean or String) - Determines if the field is required and what kind of requirement is needed.- 'exists' or a boolean of
true
- The field must exist. A field with a blank string or a zero still meet this requirement. - 'value' - The field must exist and have a value that is not
false
, zero, or a blank string. - 'same as {field}' - The field's value must match the value of another field with the given name. This is especially useful for re-entered fields like new passwords. The braces should not be included around the field name.
- 'different than {field}' - The field's value must NOT match the value of another field with the given name. The braces should not be included around the field name.
- 'with {field}' - The given field must exist or this field will fail. The braces should not be included around the field name.
- 'without {field}' - The given field must NOT exist or this field will fail. The braces should not be included around the field name.
- 'exists' or a boolean of
format
(String) - Checks the contents of the field's value to match a specific pattern.- 'domain' - This matches a second-level domain, like 'example.com', but not lower-levels, like 'example.co.uk'. See
isDomain
for details. - 'hostname' - Matches hostnames according to the
isHostname
function. - 'email' - Matches email addresses according to the
isEmail
function. - 'http url' - Matches HTTP URLS, or web site addresses, according to the
isHttpURL
function. - 'integer' - Matches numbers according to the
isInteger
function. - 'positive integer' - Matches numbers according to the
isPositiveInteger
function. - 'negative integer' - Matches numbers according to the
isNegativeInteger
function.
- 'domain' - This matches a second-level domain, like 'example.com', but not lower-levels, like 'example.co.uk'. See
regexp
(RegExp) - Checks the contents of the field's value to match the given regular expression. This can be used in conjunction withformat
. For example, ifformat
is set to 'email' andregexp
is set to /@example.com/, anything other than a valid email address at example.com will fail. This only works on fields oftype
'string'.values
(Array) - An array of whitelisted values. This takes precedence overformat
andregexp
.actions
(Array of Strings) - An array of actions to perform on fields oftype
'string'. The actions occur in array order.- 'lowercase' - Convert the field's value to lowercase letters.
- 'uppercase' - Convert the field's value to uppercase letters.
- 'strip' - Strips leading and trailing whitespace from the field's value.
Output
The output is an object with the following items.
data
- The converted version of original input object. Only fields in the field definitions that pass their validation are included.error
- An object containing items for each failed field test. Keys in the object are the names of the fields that failed and the values are the test on which it failed. For example, if a field named 'password' hasrequire
set to 'value' and no value is submitted,error
would at least contain a key ofpassword
with a value of 'require'. This can be used to generate error messages for a user.messages
- An array of English error messages. This is the lazy way of displaying errors instead of using theerror
object to assemble your own.isModified
- A boolean that istrue
if any field values indata
were modified from the original input object.
Examples of field definitions
For a full example, check the Quick Examples section.
Example: Limiting fields in input
When receiving input from an API, you may want to make sure the incoming data only contains the fields you want in the right Javascript type. In this case, regardless of what is submitted, the returned object will only contain the three fields in the appropriate types.
var fields = [
{
name: 'first_name',
type: 'string'
}, {
name: 'last_name',
type: 'string'
}, {
name: 'age',
type: 'number'
}
];
Example: Requiring fields to have a value
Using the previous example, making 'first_name' and 'last_name' required is a matter of adding require
to each field definition. However, setting it to 'exists' or a boolean of true
only makes sure the field exists, but does not require a value to be in the field. To require a non-blank or non-zero value, use 'value'.
var fields = [
{
name: 'first_name',
type: 'string',
require: 'value'
}, {
name: 'last_name',
type: 'string',
require: 'value'
}, {
name: 'age',
type: 'number'
}
];
Example: Requiring fields to have the same value
Sometimes a requirement may be based on another field. For example, with two password fields, named password
and password_retype
, you could require the second match.
var fields = [
{
name: 'password',
type: 'string',
require: 'value'
}, {
name: 'password_retype',
type: 'string',
require: 'same as password'
}
];
Example: Restricting field values by format
The value of fields can be restricted even further by requiring the input to match a certain pattern. Check for invalid email addresses or an age that isn't a positive integer using format
.
var fields = [
{
name: 'email_address',
type: 'string',
require: 'value',
format: 'email'
}, {
name: 'age',
type: 'number',
require: 'value',
format: 'positive integer'
}
];
Example: Restricting field values by regular expression
Using regexp
, restrict the content of a field by regular expressions. In this example, make sure the first name only contains letters.
var fields = [
{
name: 'first_name',
type: 'string',
require: 'value',
regexp: /^[a-zA-Z]+$/
}
];
Example: Restricting field values by a whitelist
If there is a limited number of possible answers, a whitelist may be the best choice. A menu or radio buttons in a web form may only contain certain values, but that doesn't prevent someone from submitting other values if they know what they are doing. You can prevent that from happening with a whitelist.
var fields = [
{
name: 'color',
type: 'string',
values: ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']
}
];
Example: Modifying field values with actions
Sometimes users accidentally hit a space after what they type or type with caps lock on. To prevent dumb entry problems from becoming errors, you can use actions to clean up the input automatically. For example, an email address or username shouldn't contain extra whitespace and isn't usually case sensitive. However, when comparing input against an existing record, whitespace and capitalization can prevent a match. Using actions
can normalize the input to prevent that from being a problem. In this case, use the 'strip' action to remove leading and trailing whitespace and use the 'lowercase' action to make the input all lowercase.
var fields = [
{
name: 'username',
type: 'string',
require: 'value',
actions: ['strip', 'lowercase']
}
];
Release History
0.1 First version
License
Copyright (c) 2015 Tim Moses
Licensed under the GNU license.