validata
v5.0.8
Published
Type safe data validation and sanitization
Downloads
2,999
Maintainers
Readme
Validata
Type safe data validation and sanitization.
See also
- validata-koa for more usage in Koa
- validata-express for more usage in Express
Getting started
npm i validata
Basic usage
import { asString, isObject, isString, maybeString } from 'validata';
interface Sample {
maybeString: string | undefined;
myString: string;
numericString: string;
}
const sample = isObject<Sample>({
maybeString: maybeString(), // will allow string data type or sanitize to undefined
myString: isString(), // will allow only string data type
numericString: asString(), // will allow string or attempt to convert to string
});
console.log(
JSON.stringify(
sample.process({
maybeString: 123,
myString: 123,
numericString: 123,
})
)
);
/*
FAIL: Outputs:
{"issues":[{"path":["maybeString"],"value":123,"reason":"incorrect-type","info":{"expectedType":"string"}},{"path":["myString"],"value":123,"reason":"incorrect-type","info":{"expectedType":"string"}}]}
*/
console.log(
JSON.stringify(
sample.process({
myString: '123',
numericString: 123,
})
)
);
/*
SUCCESS: Outputs:
{"value":{"myString":"123","numericString":"123"}}
*/
API
Checks:
- isAny
- Array
- isArray
- maybeArray
- asArray
- maybeAsArray
- Boolean
- isBoolean
- maybeBoolean
- asBoolean
- maybeAsBoolean
- Date
- isDate
- maybeDate
- asDate
- maybeAsDate
- Enum
- isEnum
- maybeEnum
- asEnum
- maybeAsEnum
- Number
- isNumber
- maybeNumber
- asNumber
- maybeAsNumber
- Object
- isObject
- maybeObject
- asObject
- maybeAsObject
- Record
- isRecord
- maybeRecord
- asRecord
- maybeAsRecord
- String
- isString
- maybeString
- asString
- maybeAsString
- Tuple
- isTuple
- maybeTuple
- Url
- isUrl
- maybeUrl
- asUrl
- maybeAsUrl
- isNullable
- asNullable
Types
- TypeOf
Work is done by a typed ValueProcessor
, as returned byisObject<T>()
or asNumber()
.
interface ValueProcessor<T> {
process(value: unknown): Result<T>;
}
The process()
method returns a Result<T>
.The Result
is either a list of issues
(meaning validation failures) or the accepted value (it may be coerced/altered from the original).
type Result<T> = ValueResult<T> | IssueResult;
interface ValueResult<T> {
value: T;
}
interface IssueResult {
issues: Issue[];
}
Naming conventions
is...
e.g. isNumber
- if the value is of the type it will be accepted
null
orundefined
cause an issue- otherwise it will cause an issue
maybe...
e.g. maybeNumber
- if the value is of the type it will be accepted
null
orundefined
it will sanitized to undefined- otherwise it will cause an issue
as...
e.g. asNumber
- if the value is of the type it will be accepted
null
orundefined
converted to default, if provided, or cause an issue- if the value can be converted to the type, it will be converted and used
- if the value is cannot be converted the default will be used if provided
- otherwise it will cause an issue
maybeAs...
e.g. maybeAsNumber
- if the value is of the type it will be accepted
null
orundefined
converted to default, if provided, or sanitized to undefined- if the value can be converted to the type it will be converted and used
- if the value is cannot be converted the default will be used if provided
- otherwise it will cause an issue // * otherwise it will be sanitized to undefined
Checks
isArray
, maybeArray
, asArray
, maybeAsArray
Usage:
isArray(itemProcessor, options);
maybeArray(itemProcessor, options);
asArray(itemProcessor, options);
maybeAsArray(itemProcessor, options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined orundefined
is returned then built in conversions will be runconvertOptions
- options to pass to the convertercoerceMaxLength? number
- if there are more items than this, some will be removedmaxLength?: number
- if there are more items than this, it's an errormax-length
minLength?: number
- if there are less items than this, it's an errormin-length
validator?: (value: T, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
Example:
isArray<number>(isNumber({ max: 20, min: 10 }), { coerceMaxLength: 7 });
isBoolean
, maybeBoolean
, asBoolean
, maybeAsBoolean
Usage:
isBoolean(options);
maybeBoolean(options);
asBoolean(options);
maybeAsBoolean(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined orundefined
is returned then built in conversions will be runconvertOptions
- options to pass to the convertervalidator?: (value: T, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
isDate
, maybeDate
, asDate
, maybeAsDate
Usage:
isDate(options);
maybeDate(options);
asDate(options);
maybeAsDate(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined orundefined
is returned then built in conversions will be runconvertOptions
- options to pass to the converterformat
- custom date format used in conversion fromstring
toDate
see Luxon formattingmaxFuture?: Duration
- if the value is after this duration into the future, it's an errormax-future
maxPast?: Duration
- if the value is before this duration into the past, it's an errormax-past
validator?: (value: T, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
isEnum
, maybeEnum
, asEnum
, maybeAsEnum
Usage:
isEnum(Enum);
maybeNumber(Enum);
asNumber(Enum);
maybeAsNumber(Enum);
Example:
// String based Enum
enum EnumOne {
A = 'A',
B = 'B',
C = 'C',
}
isEnum(EnumOne); // Allows "A", "B", "C"
// Number based Enum
enum EnumTwo {
A,
B,
C,
}
isEnum(EnumTwo); // Allows 0, 1, 2
// Converting to an Enum using it's key or value
asEnum(EnumTwo); // Allows 1, 2, 3, "A", "B", "C"
asEnum(EnumTwo).process('A')); // { value: 0 }
asEnum(EnumTwo).process(0)); // { value: 0 }
asEnum(EnumTwo).process(EnumOne.A)); // { value: 0 }
isNumber
, maybeNumber
, asNumber
, maybeAsNumber
Usage:
isNumber(options);
maybeNumber(options);
asNumber(options);
maybeAsNumber(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined orundefined
is returned then built in conversions will be runconvertOptions
- options to pass to the convertercoerceMin?: number
- if the value is less than this, it will be set to this valuecoerceMax?: number
- if the value is more than this, it will be set to this valuemax?: number
- if the value is than this, it's an errormax
min?: number
- if the value is than this, it's an errormin
validator?: (value: T, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
isObject
, maybeObject
, asObject
, maybeAsObject
Usage:
isObject(contract, options);
maybeObject(contract, options);
asObject(contract, options); // will parse string JSON as object
maybeAsObject(contract, options); // will parse string JSON as object
// where `contract` is Record<string, ValueProcessor>
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined orundefined
is returned then built in conversions will be runconvertOptions
- options to pass to the convertervalidator?: (value: T, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
Example:
interface Sample {
myString: string;
maybeString: string | undefined;
numericString: string;
}
const check = isObject<Sample>({
maybeString: maybeString(), // if these don't match the interface TypeScript will error
myString: isString(),
numericString: asString(),
});
isRecord
, maybeRecord
, asRecord
, maybeAsRecord
Usage:
isRecord<V>(check, options);
maybeRecord<V>(check, options);
asRecord<V>(check, options);
maybeAsRecord<V>(check, options);
// where `check` is ValueProcessor<V>, and Record<string, V> is the type to be processed
Options:
keyRegex?: RegExp
- regular expression to check each key name, or it's an errorkey-regex
maxKeys?: number
- if the number of keys in the object is more than this, it's an errormax-keys
minKeys?: number
- if the number of keys in the object is more than this, it's an errormax-keys
validator?: (value: Record<string, V>, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
Example:
const check = isRecord(isString());
check.process({ foo: 'bar' });
isString
, maybeString
, asString
, maybeAsString
Usage:
isString(options);
maybeString(options);
asString(options);
maybeAsString(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined orundefined
is returned then built in conversions will be runconvertOptions
- options to pass to the converterlimitLength?: number
- if the length of the string is more than this, it will be truncated to this lengthpadStart?: StringPadding
- pad the start of the string up to given valuepadEnd?: StringPadding
- pad the end of the string up to given valuetrim?: 'start' | 'end' | 'both' | 'none'
- removes the leading and/or trailing white space and line terminator characters from the stringregex?: RegExp
- regular expression that must be matched, or it's an errorregex
maxLength?: number
- if the length of the string is more than this, it's an errormax-length
minLength?: number
- if the length of the string is less than this, it's an errormin-length
format:? StringFormatCheck
- extension point for string format checking, if check fails it's an issueformat
withinfo.expectedFormat
setvalidator?: (value: T, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
StringPadding:
length: number
- will pad up until this lengthpadWith: string
- the value to pad with
StringFormat:
StringFormat.ULID()
- https://github.com/ulid/specStringFormat.UUID()
- https://www.ietf.org/rfc/rfc4122.txtStringFormat.password(requirements: PasswordRequirements)
- Password format with minimum requirements
Example:
const check = isString({
limitLength: 6,
padStart: { length: 6, padWith: '-' },
});
const check = isString({
format: StringFormat.ULID(),
});
const check = isString({
format: StringFormat.password({
minLength: 10, // default=8
numberChars: 2, // default=1
lowerCaseChars: 2, // default=1
upperCaseChars: 2, // default=1
specialChars: 0, // default=1
}),
});
// change case
import { pascalCase } from 'change-case';
const check = isString({
transform: pascalCase,
});
const check = isString({
maxLength: 10,
minLength: 8,
regex: /^[A-Z]+$/,
});
import validator from 'validator';
const check = isString({
validator: validator.isEmail,
validatorOptions: { allow_display_name: true },
});
isTuple
, maybeTuple
Usage:
isTuple(options);
maybeTuple(options);
Options:
validator?: (value: T, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
Example:
type MyTuple = [number, string];
const check = isTuple([isNumber({ max: 9, min: 3 }), isString({ regex: /^\w+$/ })]);
isUrl
, maybeUrl
, asUrl
, maybeAsUrl
Working with Node's URL object
Usage:
isUrl(options);
maybeUrl(options);
asUrl(options);
maybeAsUrl(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined orundefined
is returned then built in conversions will be runconvertOptions
- options to pass to the convertersetProtocol?: string
- will coerce the protocol to the given value, if presentprotocol?: string
- given URL must have this protocol, or it's an errorinvalid-protocol
validator?: (value: URL, options?: any, path?: Path[]) => boolean | Issue[]
- custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- options to pass to the validator
Example:
const check = asUrl({
protocol: 'https',
});
isNullable
Any other check can be wrapped into isNullable
to accept null
.
Example:
const check = isNullable(isString({ min: 3 }));
asNullable
Any other check can be wrapped into asNullable
to accept null
.
Options:
default
- can benull
or return type or a function with return type of the wrapped check
Example:
const check = asNullable(isString({ min: 3 }));
const check = asNullable(isString({ min: 3 }), { default: null });
const check = asNullable(isString({ min: 3 }), { default: 'text' });
const check = asNullable(isString({ min: 3 }), { default: () => 'text' });
Types
Types can be extracted from a ValueProcessor
or a Contract
-like pure object.
const sampleContract = {
maybeString: maybeString(),
myString: isString(),
numericString: asString(),
};
const sample = isObject(sampleContract);
// both are same as
export type SampleContract = TypeOf<typeof sample>;
export type Sample = TypeOf<typeof sample>;
// interface Sample {
// myString: string;
// maybeString: string | undefined;
// numericString: string;
// }