Security News
New Python Packaging Proposal Aims to Solve Phantom Dependency Problem with SBOMs
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Lightweight validator supporting Language Independent Validation Rules Specification
LIVR.Validator - Lightweight JavaScript validator supporting Language Independent Validation Rules Specification (LIVR).
There are 2 implementations:
Common usage:
import LIVR from 'livr';
LIVR.Validator.defaultAutoTrim(true);
const validator = new LIVR.Validator({
name: 'required',
email: ['required', 'email'],
gender: { one_of: ['male', 'female'] },
phone: { max_length: 10 },
password: ['required', { min_length: 10 }],
password2: { equal_to_field: 'password' },
});
const validData = validator.validate(userData);
if (validData) {
saveUser(validData);
} else {
console.log('errors', validator.getErrors());
}
All standard rules are supported in camel case as well (Validator.registerDefaultRules always does autocamelization):
Camel case names are closer to JS naming conventions but underscore rule names are more compatible with LIVR spec.
import LIVR from 'livr';
LIVR.Validator.defaultAutoTrim(true);
const validator = new LIVR.Validator({
name: 'required',
email: ['required', 'email'],
gender: { oneOf: ['male', 'female'] },
phone: { maxLength: 10 },
password: ['required', { minLength: 10 }],
password2: { equalToField: 'password' },
});
const validData = validator.validate(userData);
if (validData) {
saveUser(validData);
} else {
console.log('errors', validator.getErrors());
}
Common usage of async version:
import LIVR from 'livr/async';
LIVR.AsyncValidator.defaultAutoTrim(true);
const validator = new LIVR.AsyncValidator({
name: 'required',
email: ['required', 'email'],
gender: { one_of: ['male', 'female'] },
phone: { max_length: 10 },
password: ['required', { min_length: 10 }],
password2: { equal_to_field: 'password' },
});
try {
const validData = await validator.validate(userData);
saveUser(validData);
} catch (errors) {
console.log('errors', errors);
}
You can use modifiers separately or can combine them with validation:
const validator = new LIVR.Validator({
email: ['required', 'trim', 'email', 'to_lc'],
});
Feel free to register your own rules:
You can use aliases(preferable, syntax covered by the specification) for a lot of cases:
const validator = new LIVR.Validator({
password: ['required', 'strong_password'],
});
validator.registerAliasedRule({
name: 'strong_password',
rules: { min_length: 6 },
error: 'WEAK_PASSWORD',
});
Or you can write more sophisticated rules directly:
const validator = new LIVR.Validator({
password: ['required', 'strong_password'],
});
validator.registerRules({
strong_password() {
return (value) => {
// We already have "required" rule to check that the value is present
if (value === undefined || value === null || value === '') return;
if (value.length < 6) {
return 'WEAK_PASSWORD';
}
};
},
});
Or you can write more sophisticated async rules as well:
const validator = new LIVR.AsyncValidator({
userId: ['required', 'valid_user_id'],
});
validator.registerRules({
valid_user_id() {
return async (value) => {
// We already have "required" rule to check that the value is present
if (value === undefined || value === null || value === '') return;
const user = await Users.findUserById(value);
if (!user) {
return 'WRONG_USER_ID';
}
};
},
});
If you use LIVR in browser, you can import only the rules you use (it can reduce budle size a little bit):
import Validator from 'livr/lib/Validator';
Validator.registerDefaultRules({
required: require('livr/lib/rules/common/required'),
email: require('livr/lib/rules/special/email'),
one_of: require('livr/lib/rules/string/one_of'),
min_length: require('livr/lib/rules/string/min_length'),
max_length: require('livr/lib/rules/string/max_length'),
equal_to_field: require('livr/lib/rules/special/equal_to_field'),
});
Validator.defaultAutoTrim(true);
// Anywhere in your app
import Validator from 'livr/lib/Validator';
const validator = new Validator({
name: 'required',
email: ['required', 'email'],
gender: { one_of: ['male', 'female'] },
phone: { max_length: 10 },
password: ['required', { min_length: 10 }],
password2: { equal_to_field: 'password' },
});
const validData = validator.validate(userData);
if (validData) {
saveUser(validData);
} else {
console.log('errors', validator.getErrors());
}
See LIVR Specification and rules documentation for detailed documentation and list of supported rules.
Features:
JavaScript version extra features:
LIVR supports async validation but it was added only in v2.5. So, it uses a little bit different API.
What you need to know about implementation:
Usage example:
import LIVR from 'livr/async';
LIVR.AsyncValidator.defaultAutoTrim(true);
const validator = new LIVR.AsyncValidator({
name: 'required',
email: ['required', 'email'],
});
try {
const validData = await validator.validate(userData);
saveUser(validData);
} catch (errors) {
console.log('errors', errors);
}
npm install livr
You can find prebuilt browser versions in "dist" folder
Constructor creates validator objects. rules - validations rules. Rules description is available here - https://livr-spec.org/
Supported options:
Instead of "options" object "isAutoTrim" boolean value can be passed for compatibility with previous API. if isAutoTrim is undefined(or null) then defaultAutoTrim value will be used.
alias - is a plain javascript object that contains: name, rules, error (optional).
LIVR.Validator.registerAliasedDefaultRule({
name: 'valid_address',
rules: {
nested_object: {
country: 'required',
city: 'required',
zip: 'positive_integer',
},
},
});
Then you can use "valid_address" for validation:
{
address: 'valid_address';
}
You can register aliases with own errors:
LIVR.Validator.registerAliasedDefaultRule({
name: 'adult_age'
rules: [ 'positive_integer', { min_number: 18 } ],
error: 'WRONG_AGE'
});
All rules/aliases for the validator are equal. The validator does not distinguish "required", "list_of_different_objects" and "trim" rules. So, you can extend validator with any rules/alias you like.
Note: Each rule which contains uderscore in name will be additionally registered using camel case name if there is no such rule name already.
ruleBuilder - is a function reference which will be called for building single rule validator.
Note: Each rule which contains uderscore in name will be additionally registered using camel case name if there is no such rule name already.
LIVR.Validator.registerDefaultRules({
my_rule(arg1, arg2, arg3, ruleBuilders) {
// ruleBuilders - are rules from original validator
// to allow you create new validator with all supported rules
// const validator = new LIVR.Validator(livr).registerRules(ruleBuilders).prepare();
return (value, allValues, outputArr) => {
if (notValid) {
return 'SOME_ERROR_CODE';
} else {
}
};
},
});
Then you can use "my_rule" for validation:
{
name1: 'my_rule' // Call without parameters
name2: { 'my_rule': arg1 } // Call with one parameter.
name3: { 'my_rule': [arg1] } // Call with one parameter.
name4: { 'my_rule': [ arg1, arg2, arg3 ] } // Call with many parameters.
}
Here is "max_number" implemenation:
function maxNumber(maxNumber) {
return (value) => {
// We do not validate empty fields. We have "required" rule for this purpose
if (value === undefined || value === null || value === '') return;
// return error message
if (value > maxNumber) return 'TOO_HIGH';
};
}
LIVR.Validator.registerDefaultRules({ max_number: maxNumber });
All rules for the validator are equal. The validator does not distinguish "required", "list_of_different_objects" and "trim" rules. So, you can extend validator with any rules you like.
returns object containing all default ruleBuilders for the validator. You can register new rule or update existing one with "registerRules" method.
Enables or disables automatic trim for input data. If is on then every new validator instance will have auto trim option enabled
List of useful utils for writing your rules (see source code)
Parses all validation rules to make subsequent calls faster. This step is always automatically called on first call of validator.validate(input) but you can call it manually if you want to warm up your validator object before validation was called. Usually, it is useful in several cases:
Validates user input. On success returns validData (contains only data that has described validation rules). On error return false.
const validData = validator.validate(input);
if (validData) {
// use validData
} else {
const errors = validator.getErrors();
}
for AsyncValidator
try {
const validData = await validator.validate(input);
// use validData
} catch (errors) {
// handle errors
}
Returns errors object.
{
"field1": "ERROR_CODE",
"field2": "ERROR_CODE",
...
}
For example:
{
"country": "NOT_ALLOWED_VALUE",
"zip": "NOT_POSITIVE_INTEGER",
"street": "REQUIRED",
"building": "NOT_POSITIVE_INTEGER"
}
ruleBuilder - is a function reference which will be called for building single rule validator.
See "LIVR.Validator.registerDefaultRules" for rules examples.
alias - is a composite validation rule.
See "LIVR.Validator.registerAliasedDefaultRule" for rules examples.
returns object containing all ruleBuilders for the validator. You can register new rule or update existing one with "registerRules" method.
LIVR is fast but you should be aware about following:
Do not construct Validator for each validation call. Construct object once for each schema and reuse validators with different inputs. "validator.validate(input)" is very fast.
In some cases you need to construct object each time, it is slower but still ok. It still will be twice faster than "Joi". LIVR validator preparation (rules compile step) is 100 time faster than "fastest-validator" compile time.
koorchik (Viktor Turskyi)
eNdiD
Please report any bugs or feature requests to Github https://github.com/koorchik/js-validator-livr
FAQs
Lightweight validator supporting Language Independent Validation Rules Specification
We found that livr demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Security News
Socket CEO Feross Aboukhadijeh discusses open source security challenges, including zero-day attacks and supply chain risks, on the Cyber Security Council podcast.
Security News
Research
Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.