An easy to implement and extensible Express API middleware that validates user input and permissions
The middleware iterates over a "Validation Schema" which defines endpoint-specific, router-specific, and/or Express instance-specific user input validation and permissions.
[ //Validation Schema
{ //Validation Object
if: [ //If Array
{ //If Object
...
},
...
],
then: [ //Then Array
{ //Then Object
...
},
...
]
},
...
]
- Validation Schemas are an array of Validation Objects which outlines all of the validation conditionals, actions, and responses
- There can only be one Validation Schema per endpoint, one Validation Schema per router, and/or one Validation Schema per Express API instance.
- You may use built-in validation functions which return Validation Objects
- Alternatively, you may define custom rules by writing your own Validation Objects if the library doesn't have the functionality you need built in
- Validation Objects are an array of Validation Objects make up a Validation Schema
- Validation Objects define a single rule of an overall Validation Schema
- Validation Objects are made up of two parts: one If Array and one Then Array
- The If Array and Then Array outline conditionals and the actions to be taken if the conditionals are true
- If Arrays are an array of If Objects which can be combined to form a complete conditional statement
- If the conditional statement evaluates to true...
- Then a Then Array (which contain one or more actions) is parsed and ran
- If Objects represent an incomplete part of a conditional statement
- When combined in the order they are defined...
- If Objects represent a complete conditional statement that can be evaluated
- Then Objects contain one or more actions or responses
- The actions and responses are executed if the accompanying conditional statement is evaluated to be true
- Defined using key-value pairs
- The key is the path of the variable starting after the Express Request Object (
req
) - The value is the rules that the variable must meet
- Rules can be chained together as necessary [IE. validat0r.required().number().range(1,100).userRole('admin')]
{
'query.banana': validat0r.required() //Required request param
'body.banana': validat0r.unique(dbTable, dbColumn, additionalFilter) //Must be unique
'params.banana': validat0r.exists(dbTable, dbColumn, additionalFilter) //DB row must exist
'headers.banana': validat0r.userRole(userRole) //Restrict to a certain role (admin, user, etc.)
'query.banana': validat0r.range(min,max) //Must be within a certain range, inclusive
'query.banana': validat0r.min(number) //Must be equal to or above this number
'params.banana': validat0r.max(number) //Must be equal to or below this number
'params.banana': validat0r.number() //Must be a Number
'headers.banana': validat0r.integer() //Must be an Integer
'body.banana': validat0r.boolean() //Must be a Boolean
'headers.banana': validat0r.string() //Must be a String
'body.banana': validat0r.alphaNumeric() //Must be letters and/or numbers
'body.banana': validat0r.json() //Must be JSON
'body.banana': validat0r.object() //Must be an Object
'body.banana': validat0r.array() //Must be an Array
'query.banana': validat0r.defaultTo(defaultValue) //Default to a certain value if undefined
'params.banana': validat0r.defaultToRole(userRole, defaultValue) //Default to a certain value for specific roles
'query.banana': validat0r.forceTo(defaultValue) //Reassign to a certain value
'params.banana': validat0r.forceToRole(userRole, defaultValue) //Reassign to a certain value for specific roles
'body.banana': validat0r.regex(regexString) //Must match a regular expression
'params.banana': validat0r.email(email) //Must be an email
}
{ //Validation Object
if: [ //If Array
{ //If Object
expectedValue: Boolean || String || Number || Array || JSON || undefined || null
expectedValueType: String ('literal' || 'regex')
dataType: String ('boolean' || 'string' || 'number' || 'array' || 'json' || 'undefined' || 'null')
conditional: String ('if' || 'else' || 'else if')
comparisonOperator: String ('>' || '>=' || '<' || '<=' || '==' || '===' || '!==')
logicalOperator: String ('||' || '&&')
groupingOperator: String ('(' || ')')
metaPath: String ('query' || 'body' || 'params' || 'headers' || 'db')
macroPath: String (Anything after 'req.query' || 'req.body' || 'databaseTable' (etc. for all dataTypes) *IN DOT NOTATION*)
- Can be property names or functions- IE. .length or .slice(0,1) or database API functions IE. users.getOne()
microPath: String (Anything passed into a function)
databasePath: String ('users' || 'categories' || 'challenges' || 'user_submissions' || 'challenges_categories')
}
],
then: [ //Then Array
{ //Then Object
assignment: {
metaPath: String ('query' || 'body' || 'params' || 'headers' || 'db')
macroPath: String (Anything after 'req.query' || 'req.body' || 'databaseTable' (etc. for all dataTypes) *IN DOT NOTATION*)
- Can be property names or functions- IE. .length or .slice(0,1) or database API functions IE. users.getOne()
microPath: String (Anything passed into a function)
databasePath: String ('users' || 'categories' || 'challenges' || 'user_submissions' || 'challenges_categories')
value: Boolean || String || Number || Array || JSON || undefined || null
},
rejectRequest: {
consoleLog: Boolean
throwError: Boolean
errorMessage: String
errorMessageWithLabel: String
errorCode: Integer
}
}
]
}
[
{
name: String
required: Boolean
type: String ('query' || 'body' || 'params')
dataType: String ('boolean' || 'string' || 'number' || 'integer' || 'range' || 'json' || 'alphanumeric' || 'object' || 'array')
range: [min, max]
min: Number
max: Number
userRestrictions: Array [
Object {userPath, optionalValue} Value defaults to value of property
]
userHooks: Array [
Object {conditionalString, evalString}
]
dbExists: Array [
Object {dbTable, dbColumn, additionalFilter}
]
dbUnique: Array [
Object {dbTable, dbColumn, additionalFilter}
]
dbHooks: Array [
{ dbTable, selector, column, evalString }
]
preHooks: Array [
{path, evalString}
]
postHooks: Array [
{path, evalString}
]
}
]