Type safe data validation and sanitization
npm install validataType safe data validation and sanitization.
See also
- validata-koa for more usage in Koa
- validata-express for more usage in Express
``bash`
npm i validata
`typescript
import { asString, isObject, isString, maybeString } from 'validata';
interface Sample {
maybeString: string | undefined;
myString: string;
numericString: string;
}
const sample = isObject
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"}}
*/
`
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:
`bash`
pnpm add luxon @types/luxon validata
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 or asNumber().
`typescript`
interface ValueProcessor
process(value: unknown): Result
}
The process() method returns a Result.The Result is either a list of issues
(meaning validation failures) or the accepted value (it may be coerced/altered from the original).
`typescript
type Result
interface ValueResult
value: T;
}
interface IssueResult {
issues: Issue[];
}
`
- if the value is of the type it will be accepted
- null or undefined cause an issue
- otherwise it will cause an issue
- if the value is of the type it will be accepted
- null or undefined it will sanitized to undefined
- otherwise it will cause an issue
- if the value is of the type it will be accepted
- null or undefined 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
- if the value is of the type it will be accepted
- null or undefined 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
Usage:
`typescript`
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 or undefined is returned then built in conversions will be runconvertOptions
- - options to pass to the _converter_coerceMaxLength? number
- - if there are more items than this, some will be removedmaxLength?: number
- - if there are more items than this, it's an error max-lengthminLength?: number
- - if there are less items than this, it's an error min-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:
`typescript`
isArray
Usage:
`typescript`
isBoolean(options);
maybeBoolean(options);
asBoolean(options);
maybeAsBoolean(options);
Options:
- converter?: (value: unknown, options?: any) => T | undefined - custom converter function, if not defined or undefined is returned then built in conversions will be runconvertOptions
- - options to pass to the _converter_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_
> NOTE: Requires peer dependencies luxon and @types/luxon.
Usage:
`typescript`
isDate(options);
maybeDate(options);
asDate(options);
maybeAsDate(options);
Options:
- converter?: (value: unknown, options?: any) => T | undefined - custom converter function, if not defined or undefined is returned then built in conversions will be runconvertOptions
- - options to pass to the _converter_format
- - custom date format used in conversion from string to Date see Luxon formattingmaxFuture?: Duration
- - if the value is after this duration into the future, it's an error max-futuremaxPast?: Duration
- - if the value is before this duration into the past, it's an error max-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_
Similar to above but for luxon DateTime.
> NOTE: Requires peer dependencies luxon and @types/luxon.
Usage:
`typescript`
isDateTime(options);
maybeDateTime(options);
asDateTime(options);
maybeAsDateTime(options);
Options:
- converter?: (value: unknown, options?: any) => T | undefined - custom converter function, if not defined or undefined is returned then built in conversions will be runconvertOptions
- - options to pass to the _converter_format
- - custom date format used in conversion from string to Date see Luxon formattingmaxFuture?: Duration
- - if the value is after this duration into the future, it's an error max-futuremaxPast?: Duration
- - if the value is before this duration into the past, it's an error max-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_
Usage:
`typescript`
isEnum(Enum);
maybeNumber(Enum);
asNumber(Enum);
maybeAsNumber(Enum);
Example:
`typescript
// 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 }
`
Usage:
`typescript`
isNumber(options);
maybeNumber(options);
asNumber(options);
maybeAsNumber(options);
Options:
- converter?: (value: unknown, options?: any) => T | undefined - custom converter function, if not defined or undefined is returned then built in conversions will be runconvertOptions
- - options to pass to the _converter_coerceMin?: 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 error maxmin?: number
- - if the value is than this, it's an error minvalidator?: (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_
Usage:
`typescriptcontract
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 is Record`
Options:
- converter?: (value: unknown, options?: any) => T | undefined - custom converter function, if not defined or undefined is returned then built in conversions will be runconvertOptions
- - options to pass to the _converter_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:
`typescript
interface Sample {
myString: string;
maybeString: string | undefined;
numericString: string;
}
const check = isObject
maybeString: maybeString(), // if these don't match the interface TypeScript will error
myString: isString(),
numericString: asString(),
});
`
Usage:
`typescriptcheck
isRecord
maybeRecord
asRecord
maybeAsRecord
// where is ValueProcessor`
Options:
- keyRegex?: RegExp - regular expression to check each key name, or it's an error key-regexmaxKeys?: number
- - if the number of keys in the object is more than this, it's an error max-keysminKeys?: number
- - if the number of keys in the object is more than this, it's an error max-keysvalidator?: (value: Record
- - custom validation function; if false or Issue[] is returned it's an errorvalidatorOptions?: any
- - options to pass to the _validator_
Example:
`typescript`
const check = isRecord(isString());
check.process({ foo: 'bar' });
Usage:
`typescript`
isString(options);
maybeString(options);
asString(options);
maybeAsString(options);
Options:
- converter?: (value: unknown, options?: any) => T | undefined - custom converter function, if not defined or undefined is returned then built in conversions will be runconvertOptions
- - options to pass to the _converter_limitLength?: 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 error regexmaxLength?: number
- - if the length of the string is more than this, it's an error max-lengthminLength?: number
- - if the length of the string is less than this, it's an error min-lengthformat:? StringFormatCheck
- - extension point for string format checking, if check fails it's an issue format with info.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 requirementsStringFormat.email(options: { allowDisplayName: boolean })
- - requires peer dependency validator
Example:
`typescript`
const check = isString({
limitLength: 6,
padStart: { length: 6, padWith: '-' },
});
`typescript`
const check = isString({
format: StringFormat.ULID(),
});
`typescript`
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
}),
});
`typescript`
const check = isString({
format: StringFormat.email({ allowDisplayName: false }),
});
`typescript
// change case
import { pascalCase } from 'change-case';
const check = isString({
transform: pascalCase,
});
`
`typescript`
const check = isString({
maxLength: 10,
minLength: 8,
regex: /^[A-Z]+$/,
});
`typescript
import validator from 'validator';
const check = isString({
validator: validator.isEmail,
validatorOptions: { allow_display_name: true },
});
`
Usage:
`typescript`
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:
`typescript`
type MyTuple = [number, string];
const check = isTuple([isNumber({ max: 9, min: 3 }), isString({ regex: /^\w+$/ })]);
Working with Node's URL object
Usage:
`typescript`
isUrl(options);
maybeUrl(options);
asUrl(options);
maybeAsUrl(options);
Options:
- converter?: (value: unknown, options?: any) => T | undefined - custom converter function, if not defined or undefined is returned then built in conversions will be runconvertOptions
- - options to pass to the _converter_setProtocol?: string
- - will coerce the protocol to the given value, if presentprotocol?: string
- - given URL must have this protocol, or it's an error invalid-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:
`typescript`
const check = asUrl({
protocol: 'https',
});
Any other check can be wrapped into isNullable to accept null.
Example:
`typescript`
const check = isNullable(isString({ min: 3 }));
Any other check can be wrapped into asNullable to accept null.
Options:
- default - can be null or return type or a function with return type of the wrapped check
Example:
`typescript`
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 can be extracted from a ValueProcessor or a Contract-like pure object.
`typescript
const sampleContract = {
maybeString: maybeString(),
myString: isString(),
numericString: asString(),
};
const sample = isObject(sampleContract);
// both are same as
export type SampleContract = TypeOf
export type Sample = TypeOf
// interface Sample {
// myString: string;
// maybeString: string | undefined;
// numericString: string;
// }
``