Schema (validation)
import: @azure-net/kit
Schemas are needed to validate your requests. There are two variants: createSchemaFactory and schema. The difference is in the presence of predefined validation rules. When creating a factory, you create a schema instance with rules, when creating a schema directly, you will import rules each time.
The package contains a considerable number of validation schemas, but first, let's cover the basics.
Creating a schema
// When creating a schema, you must pass the request type for typing
const LoginSchema = schema<ILoginRequest>()
.rules(() => ({
// Validation rules are written here
}))
.transform((request) => (<ILoginRequuestTransformed>{
// In the callback you receive your original incoming request
// Here you can transform the request, when calling the json method your request will be automatically converted to what you return here
// Transformation will only work if validation succeeds
}))
.with(() => ({
// In object keys you can return custom methods needed in your schema, examples will be below
}))
.create();Schema factory example
This variant is generally intended as the primary one
import { createSchemaFactory } from '@azure-net/kit';
// The createRules method creates validation rules with specific messages
// There are 3 types of messages - validationMessagesI18n, validationMessagesEn, validationMessagesRu
// validationMessagesI18n assume the use of a translation package (edges-svelte-translations)
// Initially validationMessagesI18n don't have translations and you'll need to add them
import { createRules, validationMessagesI18n } from '@azure-net/kit/schema';
export const Schema = createSchemaFactory(createRules(validationMessagesI18n));
export const LoginSchema = Schema<ILoginRequest>()
// Now in the callback you receive validation rules
.rules((rules) => ({
email: [rules.required(), rules.string(), rules.email()],
password: [rules.required(), rules.password({ length: 6 })]
}))
.create();Examples of using with
export const UpdateScriptSchema = Schema<IScriptUpdateRequest>()
.rules(() => ({
// Add validation rules here
}))
.with(() => ({
fromScriptModel: (script: IScript) => {
return <IScriptUpdateRequest>{
type: script?.type,
position: script?.position,
text: script?.text,
timeout: script?.timeout,
name: script?.name
};
}
}))
.create();
// In the component you can use methods from the schema to populate the request, which is what the fromScriptModel method is created for
const form = createActiveForm((formData: Partial<IScriptUpdateRequest>) => update(data.scriptResource.id, formData), {
initialData: UpdateScriptSchema.fromScriptModel(data.scriptResource)
});Validation rules
string(params?)
Checks that the value is a string and meets length constraints.
Parameters:
length.min— minimum length.length.max— maximum length.message— override standard messages (base,min,max).
Example:
rules.string({ length: { min: 3, max: 10 } })number(params?)
Checks that the value is an integer and falls within a range.
Parameters:
range.min— minimum value.range.max— maximum value.message— custom error messages (base,min,max).
Example:
rules.number({ range: { min: 1, max: 100 } })finite(params?)
Checks that the value is a finite number (not NaN, not Infinity) and satisfies constraints.
Parameters:
range.min/range.max— allowable value range.maxDigitsAfterDot— limit on the number of decimal places.message— message object (base,min,max,maxDigitsAfterDot).
Example:
rules.finite({ range: { min: 0, max: 100 }, maxDigitsAfterDot: 2 })boolean(params?)
Checks that the value is boolean (true/false), and optionally matches the expected value.
Parameters:
expected— if specified, checks for equality totrueorfalse.message— messages (base,expected).
Example:
rules.boolean({ expected: true })array(params?)
Checks that the value is an array, fits the length requirements, and can contain nested rules for elements.
Parameters:
length.min/length.max— array size constraints.schema— validation schema for elements:- array of rules (for primitives);
- object with rule sets (for object elements).
message— (base,min,max).
Example:
rules.array({
length: { min: 1 },
schema: {
name: [rules.string({ length: { min: 2 } })],
age: [rules.number({ range: { min: 18 } })]
}
})phone(params?)
Checks that the string is a valid phone number with a valid country code.
Parameters:
message— function for error text. Uses internal list of codes frommasks.
Example:
rules.phone()email(params?)
Checks that the string matches email format.
Parameters:
message— function for error text.
Example:
rules.email()lettersOnly(params?)
Checks that the string contains only letters (Latin and Cyrillic). Can allow spaces.
Parameters:
whiteSpaces— whether to allow spaces.message— function withwhiteSpacesargument.
Example:
rules.lettersOnly({ whiteSpaces: true })allowedOnly(params?)
Checks that the value is in the list of allowed values.
Parameters:
allowed— array of allowed values.message— function withallowed.join(', ')argument.
Example:
rules.allowedOnly({ allowed: ['A', 'B', 'C'] })sameAs(params)
Checks that the value matches another field in the form/object.
Parameters:
key— key (field name) to compare with.message— function that accepts the key name.
Example:
rules.sameAs({ key: 'password' })notSameAs(params)
Opposite of sameAs. Checks that the value does not match the specified field.
Parameters:
key— field name to compare with.message— function that accepts the key name.
Example:
rules.notSameAs({ key: 'oldPassword' })required(params?)
Checks that the value exists and is not empty. You can specify a condition under which the field is required.
Parameters:
byCondition— function returningtrue/false(when to apply the rule).message— function without arguments.
Example:
rules.required({
byCondition: ({ listValues }) => listValues?.hasDelivery === true
})password(params?)
Checks password complexity against several criteria.
Parameters:
length— minimum length (default8).specialChars— require special characters (true/number).numbers— require digits (true/number).lowerUpperCasePattern— require combination of upper and lower case.message— object with functions (length,specialChars,numbers,lowerUpperCasePattern).
Example:
rules.password({
length: 10,
specialChars: 2,
numbers: true,
lowerUpperCasePattern: true
})Complete schema examples
export const LoginSchema = Schema<ILoginRequest>()
.rules((rules) => ({
email: [rules.required(), rules.string(), rules.email()],
password: [rules.required(), rules.password({ length: 6 })]
}))
.create();
export const CreateJobRequestSchema = Schema<IJobRequestCreateRequest>()
.rules((rules) => ({
title: [rules.required(), rules.string()],
contact_info: [rules.required(), rules.string()],
price: [rules.finite({ maxDigitsAfterDot: 2 })],
benefits: [rules.string()],
deadline_at: [rules.string()],
description: [rules.string()],
full_description: [rules.string()],
request_type: [
rules.string(),
rules.allowedOnly({
allowed: [JobRequestType.CONSULTATION, JobRequestType.INVESTMENT, JobRequestType.OTHER, JobRequestType.SERVICE, JobRequestType.PARTNERSHIP]
})
],
other_type: [rules.string()],
currency: [rules.string()]
}))
.transform((req) => ({ ...req, price: Number(req.price) }))
.create();Validation
There are several options for schema validation. First, you need to pass your request to the schema using the from method.
LoginSchema.from(data)Then you have access to 3 methods
- json automatically validates and calls transform on your request in case of success, returns data as json even if you passed FormData
- formData also automatically validates and calls transform on your request in case of success, but returns data as formData
- validated() performs validation and returns validation information
LoginSchema.from(data).json() // Validation plus data in json, in case of failure will throw SchemaFail exception which is automatically handled by createAsyncAction and returns errors in error.fields
LoginSchema.from(data).formData() // Validation plus data in formData
const {valid, errors, json, formData} = LoginSchema.from(data).validated()validated returns 4 keys
- json and formData repeat the logic described above and simply allow transforming data after validation
- valid - boolean indicating whether the request passed validation
- errors - list of field errors if the request failed validation