Skip to content

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

typescript
// 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

typescript
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

typescript
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:

typescript
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:

typescript
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:

typescript
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 to true or false.
  • message — messages (base, expected).

Example:

typescript
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:

typescript
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 from masks.

Example:

typescript
rules.phone()

email(params?)

Checks that the string matches email format.

Parameters:

  • message — function for error text.

Example:

typescript
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 with whiteSpaces argument.

Example:

typescript
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 with allowed.join(', ') argument.

Example:

typescript
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:

typescript
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:

typescript
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 returning true/false (when to apply the rule).
  • message — function without arguments.

Example:

typescript
rules.required({
  byCondition: ({ listValues }) => listValues?.hasDelivery === true
})

password(params?)

Checks password complexity against several criteria.

Parameters:

  • length — minimum length (default 8).
  • 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:

typescript
rules.password({
  length: 10,
  specialChars: 2,
  numbers: true,
  lowerUpperCasePattern: true
})

Complete schema examples

typescript
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.

typescript
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
typescript
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