validata
v6.0.4
Published
Type safe data validation and sanitization
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 validataBasic 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"}}
*/Upgrading to v6
V6 of validata has been marked as a breaking change as it moves the packages luxon, @types/luxon and validata from dependencies to peerDependencies. This better supports different package versions.
If you are using any of the validators that use these packages, you will need to install them directly into your project:
pnpm add luxon @types/luxon validataAPI
Checks:
- isAny
- Array
- isArray
- maybeArray
- asArray
- maybeAsArray
- Boolean
- isBoolean
- maybeBoolean
- asBoolean
- maybeAsBoolean
- Date
- isDate
- maybeDate
- asDate
- maybeAsDate
- DateTime
- isDateTime
- maybeDateTime
- asDateTime
- maybeAsDateTime
- 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
nullorundefinedcause an issue- otherwise it will cause an issue
maybe... e.g. maybeNumber
- if the value is of the type it will be accepted
nullorundefinedit 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
nullorundefinedconverted 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
nullorundefinedconverted 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 orundefinedis 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-lengthminLength?: number- if there are less items than this, it's an errormin-lengthvalidator?: (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 orundefinedis 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
NOTE: Requires peer dependencies
luxonand@types/luxon.
Usage:
isDate(options);
maybeDate(options);
asDate(options);
maybeAsDate(options);Options:
converter?: (value: unknown, options?: any) => T | undefined- custom converter function, if not defined orundefinedis returned then built in conversions will be runconvertOptions- options to pass to the converterformat- custom date format used in conversion fromstringtoDatesee Luxon formattingmaxFuture?: Duration- if the value is after this duration into the future, it's an errormax-futuremaxPast?: Duration- if the value is before this duration into the past, it's an errormax-pastvalidator?: (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
isDateTime, maybeDateTime, asDateTime, maybeAsDateTime
Similar to above but for luxon DateTime.
NOTE: Requires peer dependencies
luxonand@types/luxon.
Usage:
isDateTime(options);
maybeDateTime(options);
asDateTime(options);
maybeAsDateTime(options);Options:
converter?: (value: unknown, options?: any) => T | undefined- custom converter function, if not defined orundefinedis returned then built in conversions will be runconvertOptions- options to pass to the converterformat- custom date format used in conversion fromstringtoDatesee Luxon formattingmaxFuture?: Duration- if the value is after this duration into the future, it's an errormax-futuremaxPast?: Duration- if the value is before this duration into the past, it's an errormax-pastvalidator?: (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 orundefinedis 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 errormaxmin?: number- if the value is than this, it's an errorminvalidator?: (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 orundefinedis 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 processedOptions:
keyRegex?: RegExp- regular expression to check each key name, or it's an errorkey-regexmaxKeys?: number- if the number of keys in the object is more than this, it's an errormax-keysminKeys?: number- if the number of keys in the object is more than this, it's an errormax-keysvalidator?: (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 orundefinedis 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 errorregexmaxLength?: number- if the length of the string is more than this, it's an errormax-lengthminLength?: number- if the length of the string is less than this, it's an errormin-lengthformat:? StringFormatCheck- extension point for string format checking, if check fails it's an issueformatwithinfo.expectedFormatsetvalidator?: (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 requirementsStringFormat.email(options: { allowDisplayName: boolean })- requires peer dependencyvalidator
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
}),
});const check = isString({
format: StringFormat.email({ allowDisplayName: false }),
});// 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 orundefinedis 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-protocolvalidator?: (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 benullor 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;
// }