audit-var
v2.3.1
Published
Inspects variables according to a defined structure
Downloads
4
Maintainers
Readme
audit-var
Validates the type and structure of an incoming object. It's specially useful to validate the incoming data in endpoints of an API Rest, or in any other escenario when it's possible to receive an unexpected potentially manipulated data from the requester.
This library now is an ESM, so if you need CJS support, then use this version instead.
Contents
The problem
Usually, when you make an endpoint (with express for example) you need to validate the incoming data before to modify your server state. In those cases, just the validation part taken a lot of space in your file, for example:
import express, { json } from 'express';
const app = express();
app.use(json({ strict: false }));
// An interface to declare the expected structure of the body
interface Body {
id: number;
text: string;
}
// The endpoint
app.get('/test', (req, res) => {
// Validate manually the incoming object
const body = req.body as Body;
if (body == null) {
throw new Error('invalid object!');
}
if (typeof body.id !== 'number') {
throw new Error('id (typeof "number") expected!');
} else if (body.id <= 0) {
throw new Error('invalid id!');
}
if (typeof body.text !== 'string') {
throw new Error('text (typeof "string") expected!');
} else if (body.text.length < 10) {
throw new Error('text minimum length = 10 chars!');
}
// Bla bla bla bla
// Bla bla bla bla
// Bla bla bla bla
});
The solution
With audit-var you can apply the same validation in a less space. For example, taking the code of above and using audit-var, could be like this:
import express, { json } from 'express';
import { Auditor } from 'audit-var';
const app = express();
app.use(json({ strict: false }));
// Declare your auditor
const auditor = new Auditor({
type: 'object',
keys: {
id: { type: 'number', min: 1 },
text: { type: 'string', min: 10 },
}
});
// The endpoint
app.get('/test', (req, res) => {
// Checking if req.body meets the criteria settled
// in the Auditor instance
const body = auditor.audit(req.body);
// Bla bla bla bla
// Bla bla bla bla
// Bla bla bla bla
});
How to use
To install this package, use this command:
npm i --save audit-var
The class Auditor
makes all the job, you just must to import that class, and pass to the constructor an object that describes the type of data do you want to validate. The incoming objects compatibles with the Auditor
class are:
'date'
.'number'
.'string'
.'boolean'
.'array'
.'object'
.'record'
.
As much as the Array, Object and Record types, both have support to nested arrays and objects. So with this approach you can declare complex structures as you need.
So, to declare the data expected, the Auditor
class receives an object as parameter (implements BaseType<T>
interface), like this:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
// The type of value expected
type: 'string',
// Defaults false
optional: true,
// Bla bla bla
// Bla bla bla
// Bla bla bla
});
First you need to set this parameters (defined in BaseType<T>
interface):
type
(required): (read below);Sets the type of data do you want to expect. You can set any value described in this list. When you sets this value, your code editor will shows the options available of the according type selected. If the incoming value doesn't match the type specified, the
Auditor
instance will throws anInvalidTypeError
instance.optional
(optional):boolean
;By default this value is
false
. When this option isfalse
, and the incoming value isnull
orundefined
, theAuditor
instance will throws anNotOptionalError
instance. Otherwise, the methodauditor.audit(...);
will returns an undefined value either if the incoming value isnull
orundefined
.
These options are defined in BaseType<T>
interface, so you must provide in the constructor an object that implements that interface. So, the object you can provide must be one of the following (these implements BaseType<T>
):
Type 'boolean'
Boolean types doesn't have additional options. An example of usage:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'boolean',
optional: true
});
Type 'string'
Options:
min
(optional):number
;If the incoming string has a length lower than the value setted, the
Auditor
instance will throws anWrongLengthError
instance.max
(optional):number
;If the incoming string has a length higher than the value setted, the
Auditor
instance will throws anWrongLengthError
instance.cut
(optional):boolean
;If this option is enabled, when the length of the incoming string is longer than the
max
value settled, the output value will be cutted instead to throws an error.trim
(optional):boolean
;Trims the incoming string before to make any length validation.
Example:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'string',
min: 4,
max: 20,
trim: true,
});
Type 'number'
Options:
min
(optional):number
;If the incoming value has lower than the value setted, the
Auditor
instance will throws anWrongLengthError
instance.max
(optional):number
;If the incoming value has higher than the value setted, the
Auditor
instance will throws anWrongLengthError
instance.
Example:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'number',
min: 0,
max: 999
});
Type 'date'
Options:
fromJSON
(optional):boolean
;If this value is
true
, theAuditor
instance will try to parse strings with a valid JSON Date format (like'2022-12-31T03:00:00.000Z'
). If the convertion is sucessfull, the returned value will be aDate
type, otherwise, theAuditor
instance will throws anInvalidJSONDateError
instance.
Example:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'date',
fromJSON: true
});
Type 'array'
Options:
items
(required):BaseType<T>
;With this option you can specify the structure of every item stored in the array, using the same options described in the past types described. You can declare nested arrays, object arrays, or nested dictionaries too.
min
(optional):number
;If the incoming array has a length lower than the value setted, the
Auditor
instance will throws anWrongLengthError
instance.max
(optional):number
;If the incoming array has a length higher than the value setted, the
Auditor
instance will throws anWrongLengthError
instance.
Example 01 (array of string
):
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'array',
min: 10,
max: 100,
items: {
type: 'string',
min: 4
}
});
Example 02 (array of number[]
):
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'array',
items: {
type: 'array',
min: 4,
max: 4,
items: {
type: 'number',
optional: true
}
}
});
Example 03 (array of object
):
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'array',
items: {
type: 'object',
keys: {
id: { type: number, min: 1 },
name: { type: string, min: 4 }
}
}
});
Type 'object'
Options:
keys
(required):Record<string, BaseType<T>>
;Defines the type of data expected for every key of the incoming object.
Example 01:
import { Auditor } from 'audit-var';
// The expected incoming object
interface Expected {
id: number;
name: string;
active?: boolean;
}
// How to declare the Auditor instance
export const auditor = new Auditor({
type: 'object',
keys: {
id: { type: 'number', min: 1 },
name: { type: 'string', min: 4 },
active: { type: 'boolean'. optional: true}
}
});
Example 02 (nested objects):
import { Auditor } from 'audit-var';
// The expected incoming object
interface Incoming {
id: number;
config: {
path: string;
silent?: boolean;
}
data: {
id: number;
value: string;
}
}
// How to declare the Auditor instance
export const auditor = new Auditor({
type: 'object',
keys: {
id: { type: 'number', min: 1 },
config: {
type: 'object',
keys: {
path: { type: 'string' },
silent: { type: 'boolean', optional: true }
}
},
data: {
type: 'array',
items: {
type: 'object',
keys: {
id: { type: 'number' },
value: { type: 'string' }
}
}
}
}
});
Type 'record'
Options:
items
(required):BaseType<T>
;With this option you can specify the structure of every item stored for each key inside of the object, using the same options described in the past types described. You can declare nested arrays, object arrays, or nested dictionaries too.
import { Auditor } from 'audit-var'; // The incoming data const target = { joder: { id: 666, nick: 'ghostlug' }, shavo: { id: 666, nick: 'dir en grey' }, }; // The auditor const auditor = new Auditor({ type: 'record', items: { type: 'object', keys: { id: { type: 'number' }, nick: { type: 'string' } } } });
Type 'enum'
The 'enum'
type allows for the validation of values against a predefined set of allowed values. This set can include primitives (such as strings and numbers), arrays, objects, or even dates, providing flexibility for different validation scenarios. The 'enum'
type ensures the value being validated exactly matches one of the values in the specified set.
Options:
values
(required):Array<any>
;An array containing the valid values for the enum. The values can be of any type, allowing for the validation of complex structures and data types.
optional
(optional):boolean
;By default, this value is
false
. When set totrue
, and the incoming value isnull
orundefined
(and those values are not explicitly included in thevalues
array), theAuditor
instance will returnundefined
. This behavior allows fields to be omitted without causing validation errors. Ifoptional
is set tofalse
and the incoming value is eithernull
,undefined
, or not included in thevalues
array, theAuditor
instance will throw an error, enforcing strict presence and value validation.
Example with primitive values:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'enum',
values: ['active', 'inactive', 'pending'] as const,
optional: true
});
Example with objects:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'enum',
values: [
{ status: 'active', code: 1 },
{ status: 'inactive', code: 2 }
] as const
});
Example with arrays:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'enum',
values: [
[1, 2, 3],
['a', 'b', 'c']
] as const
});
Example with dates:
import { Auditor } from 'audit-var';
export const auditor = new Auditor({
type: 'enum',
values: [
new Date('2023-01-01T00:00:00.000Z'),
new Date('2023-12-31T23:59:59.999Z')
] as const
});
Utilities
this.structure
Gets the actual structure of the current instance. Whith this you attach them to another more complex instance.
const auditorChild = new Auditor({
type: 'object',
keys: {
id: { type: 'number', min: 1 },
text: { type: 'string' }
}
});
const auditorParent = new Auditor({
type: 'object',
keys: {
objA: auditor.child.structure,
objB: auditor.child.structure,
}
});