Comment on page
Schema
Delightfully simple, feature packed and customisable tool for validation and sanitization of any kind of data. Can be used on the client side as well as on the server side.
- Works with React, React Native, Angular, Vue or NodeJs
- Plentitude of validation methods for different data types
- Many useful sanitization methods for data normalization
- Typed from tail to toe for amazing developer experience
- Very intuitive and easy to use
- Extremely flexible and extendable
- Supports sync and async logic
- Encourages you to build reusable schemas
- Combine multiple schemas into more complex ones
- Conditionally connect schemas for complex scenarios
- Write custom validation and sanitization logic with ease
- Easily override error messages
- Comes translated into 6 different languages (English, German, French, Italian, Spanish and Russian)
- Easily add a new language or override translation
yarn
npm
yarn add @corets/schema
npm install --save @corets/schema
There are two ways to run validations. For simple things like one-liners where you simply want to know if a value matches certain criteria, and get a
true
or false
as result, you can use the Schema.test()
method. For proper validation, with error messages instead of a simple true
/ false
, you can use the Schema.validate()
method.Every schema specialises on a specific data type and comes with various assertion and sanitization methods. Some methods you'll be able to find on every schema, others are exclusive to a specific kind of schema.
Assertions are used for validation purposes to ensure that a value is valid.
Sanitization methods are called before validation and are used to normalise the underlying values. For example, you can ensure that a string is capitalised and all object keys are camel-cased. Sanitization can help you reduce the number of validation errors by proactively fixing them in the first place. All sanitization methods start with the prefix
to
, for example: string.toTrimmed()
, string.toCamelCase()
.Check out this React form library, it has a support for schemas and changes the way you work with forms:
Here is an example of all the available schemas and how to import them:
import {
string,
number,
array,
boolean,
date,
object,
mixed
} from "@corets/schema"
Let's describe a simple user object.
- Property email must be of type string and a valid email address
- Property fullName must be a string between 3 and 100 characters
- Property roles must be an array containing at least one role, valid roles are admin, publisher and developer, no duplicates are allowed
- Property tags must be an array of strings, each at least 3 characters long and consisting of letters and dashes
This schema contains some validation as well as some sanitization logic.
import { array, object, string } from "@corets/schema"
const roles = ["admin", "publisher", "developer"]
const userSchema = object({
email: string().email(),
fullName: string().min(3).max(100),
roles: array().min(1).someOf(roles).toUnique(),
tags: array(string().min(3).alphaDashes())
})
Quick check if an object is valid according to the schema:
const valid = userSchema.test({ ... })
if (valid) {
// continue ...
}
Get a detailed list of errors:
const errors = userSchema.validate({ ... })
if ( ! errors) {
// continue ...
}
The errors object would look something like this:
{
"field": ["first error", "second error"],
"nested.field": ["first error", "second error"],
}
Run sanitizers without any validation:
const sanitizedValue = userSchema.sanitize({ ... })
Test, validate and sanitize at the same time:
const [valid, sanitizedValue] = userSchema.sanitizeAndTest({ ... })
const [errors, sanitizedValue] = userSchema.sanitizeAndValidate({ ... })
Schemas can be freely combined with one another. When describing arrays and objects there is no way around this. Here is an example of two schemas being combined:
import { array, string } from "@corets/schema"
const usernameSchema = string().alphaNumeric().between(3, 10)
const usernameListSchema = array(usernameSchema).min(3)
const errors = usernameListSchema.validate(["foo", "bar", "baz"])
Consider writing schemas that are reusable.
Schemas can be logically linked together using methods
Schema.and()
, Schema.or()
and Schema.also()
. A Schema.and()
relation will only be executed if the parent schema, that it is linked to, could validate successfully. A Schema.or()
relation will only execute if the parent schema failed, the alternative schema will be attempted instead. A Schema.also()
relation will execute regardless of the validation status of the parent schema.Example of a
Schema.and()
relation, this schema will first ensure that the value is a string, and only if the first validation passes, it will test if the value is a numeric string:import { string } from "@corets/schema"
string().and(string().numeric())
Example of a
Schema.or()
relation, this schema will first check if the value is a number, and only if it's not, it will test if that value is a numeric string:import { number, string } from "@corets/schema"
number().or(string().numeric())
Example of an
Schema.also()
relation, this schema will execute both parts regardless of the validation outcome of the parent schema:import { string } from "@corets/schema"
string().also(string().numeric())
Conditional schemas can be wrapped into a function, this allows you to define schemas dynamically during the validation:
import { string } from "@corets/schema"
string().and(() => string().numeric())
string().or(() => string().numeric())
string().also(() => string().numeric())
You can freely define validations and sanitizers at runtime using logical links.
Logical links can be used to attach custom validation logic:
import { string } from "@corets/schema"
string().min(3).max(20)
.and(async (v) => await isUsernameTaken(v) && "Username is already taken")
Methods
Schema.and()
, Schema.or()
and Schema.also()
do not always have to return another schema. They can be used for your custom validation functions. A custom validation function can return either another schema, a validation result, or an error message.Example of a validation function returning an error message:
import { number } from "@corets/schema"
const customValidation = (value: any) => value < 12 && "Must be bigger than 12"
number().and(customValidation)
number().or(customValidation)
number().also(customValidation)
You can also return multiple error messages at once using an array.
Example of a validation function returning a schema:
import { string } from "@corets/schema"
const customValidation = (value: any) => value.includes("@") && string().email()
string().and(customValidation)
string().or(customValidation)
string().also(customValidation)
Example of a validation function returning schema validation errors:
import { string } from "@corets/schema"
const customValidation = (value: any) =>
value.includes("@") && string().email().verify(value)
string().and(customValidation)
string().or(customValidation)
string().also(customValidation)
You can add a custom sanitizer with the method
Schema.map()
, here is an example of a sanitizer that converts everything to a string:import { string } from "@corets/schema"
const customSanitizer = (value: any) => value.toString()
const sanitizedValue = string().map(customSanitizer).sanitize(1234)
All the translation logic is handled by this library:
You can change default language:
import { schemaTranslator } from "@corets/schema"
schemaTranslator.setLanguage("en")
You can also request a specific language during validation:
import { string } from "@corets/schema"
string().validate("foo", { language: "ru", fallbackLanguage: "en" })
string().verify("foo", { language: "ru", fallbackLanguage: "en" })
string().sanitizeAndValidate("foo", { language: "ru", fallbackLanguage: "en" })
string().sanitizeAndVerify("foo", { language: "ru", fallbackLanguage: "en" })
Get a full list of all translations:
import { schemaTranslator } from "@corets/schema"
console.log(schemaTranslator.getTranslations())
You can find all locales here. For further examples of how to replace translations, add new languages, etc., please have a look at the @corets/translator docs.
This method simply indicates whether a value is valid or not by returning a boolean.
Example of a failed assertion:
import { string } from "@corets/schema"
const schema = string().min(3).alphaNumeric()
// false
const valid = schema.test("foo-bar")
if (valid) {
// continue ...
}
This method returns a validation result containing detailed error messages about why a value did not pass validation.
Example of a failed validation:
import { string } from "@corets/schema"
const schema = string().min(3).alphaNumeric()
const errors = schema.validate("foo-bar")
if ( ! errors) {
// continue ...
}
This is what the validation result might look like:
{
"field": ["first error", "second error"],
"nested.field": ["first error", "second error"],
}
When validating anything but an object, you'll find all the error messages under the key self.
This method works the same as
Schema.validate()
, except it returns errors in a slightly different format. This format contains additional information about each error message and can be used for further processing of validation errors.Example of a failed validation:
import { string } from "@corets/schema"
const errors = string().min(10).verify("foo")
Here is an example of how the error messages would look like:
[
{
"type": "string_min",
"message": "Must be at least \"2\" characters long",
"args": [10],
"value": "foo",
"link": undefined,
"path": undefined
}
]
This method applies sanitizers and returns the sanitized value:
import { string } from "@corets/schema"