v8n: Fluent JavaScript Validation
v8n (validation) is a JavaScript validation library offering a dead-simple, fluent API for creating complex validation rules. It supports chaining multiple rules and modifiers, allowing for highly intuitive and readable validation logic for various data types including primitives, arrays, and objects. The library provides flexible validation strategies, including boolean-based `test()`, exception-based `check()` for detailed error feedback, and `testAll()` to gather all failures, as well as asynchronous validation. Currently at version 1.5.1, v8n maintains an active development pace with incremental feature additions and bug fixes, often addressing issues related to its schema, optional, and async validation capabilities. It differentiates itself through its highly customizable nature, enabling users to extend it with custom rules, and its reusability, allowing validation chains to be exported as modules.
Common errors
-
ReferenceError: ValidationException is not defined
cause Attempting to catch or reference the old error class name `ValidationException` after it was renamed.fixChange all references from `ValidationException` to `ValidationError` and ensure `ValidationError` is imported. -
TypeError: Cannot read properties of undefined (reading 'name') at v8n(...).check(...)
cause This usually indicates that `check()` was called but no error was thrown, or the caught object is not a `ValidationError`. This could happen if `check()` was expected to return a boolean but didn't, or if the logic flow is incorrect.fixEnsure `check()` is always within a `try...catch` block and that you are checking for `instanceof ValidationError`. Remember `check()` throws on failure and returns `void` on success. -
v8n().optional().string().test('') unexpectedly returns true, but I expect validation for empty string.cause Older versions of the `optional` rule had bugs where it would ignore subsequent rules or fail to correctly handle empty strings.fixUpdate `v8n` to version 1.5.0 or later. Also, consider the `considerTrimmedEmptyString` flag on the `optional` rule for specific empty string handling needs. -
Property 'myCustomRule' does not exist on type 'V8n' or 'v8n.V8n'
cause A custom rule was defined but not properly registered with `v8n.extend()` or TypeScript types are not extended.fixEnsure `v8n.extend({ myCustomRule })` is called before using the rule. For TypeScript, you might need declaration merging (see v8n documentation on custom types).
Warnings
- breaking The `ValidationException` error class was renamed to `ValidationError`. Code catching the old exception name will fail.
- gotcha The return type of the `check()` method was incorrectly typed as boolean instead of void. This could lead to misassumptions about its return value.
- gotcha Earlier versions had bugs where the `optional` rule might incorrectly ignore subsequent validation rules or fail to validate empty strings when trimmed, leading to unexpected passes.
- gotcha In environments that don't correctly implement `Proxy` objects or due to bugs, the `Proxy` check in v8n might have always returned `true`, causing validation logic to bypass intended checks.
- gotcha The `lowercase()` and `uppercase()` rules in earlier versions used inefficient regular expressions, which could lead to performance issues or ReDoS vulnerabilities on large or malicious input strings.
Install
-
npm install v8n -
yarn add v8n -
pnpm add v8n
Imports
- v8n
const v8n = require('v8n')import v8n from 'v8n'
- ValidationError
import { ValidationException } from 'v8n'import { ValidationError } from 'v8n' - v8n.extend
import { extend } from 'v8n'; extend({ /* rules */ });import v8n from 'v8n'; v8n.extend({ /* rules */ });
Quickstart
import v8n, { ValidationError } from 'v8n';
// Basic string validation
const isGreeting = v8n().string().minLength(5).first('H').last('o');
console.log('"Hello" is a greeting:', isGreeting.test('Hello')); // true
// Array and number validation with modifiers
const allEvenAndPositive = v8n().array().every.number().not.some.negative();
console.log('[2, 4, 6] are all even and positive:', allEvenAndPositive.test([2, 4, 6])); // true
console.log('[1, 2, -3] are all even and positive:', allEvenAndPositive.test([1, 2, -3])); // false
// Object schema validation
const userSchema = v8n().schema({
id: v8n().string().alphanumeric().minLength(4),
age: v8n().number().between(18, 99).optional()
});
console.log('Valid user object:', userSchema.test({ id: 'user123', age: 30 })); // true
console.log('Invalid user object:', userSchema.test({ id: 'abc' })); // false
// Exception-based validation
try {
v8n().string().first('b').check('foo');
} catch (ex) {
if (ex instanceof ValidationError) {
console.log('Validation failed for rule:', ex.rule.name); // first
}
}
// Custom rule extension
function isBar() {
return value => value === 'bar';
}
v8n.extend({ isBar });
console.log('"bar" is "bar":', v8n().string().isBar().test('bar')); // true