Files
michaelschiemer/docs/modules/validation.md
Michael Schiemer 36ef2a1e2c
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
fix: Gitea Traefik routing and connection pool optimization
- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
2025-11-09 14:46:15 +01:00

9.6 KiB

Validation Module

Standalone Validation System for Fields, Forms, and Data

The Validation Module provides a comprehensive validation system that can be used independently or integrated with form-handling and LiveComponents.


Features

  • Schema-Based Validation - Define validation rules in a schema
  • Field-Level Validation - Validate individual fields
  • Async Validation - Support for asynchronous validation (e.g., API checks)
  • Custom Validation Rules - Register your own validation rules
  • Integration with form-handling - Works seamlessly with form-handling module
  • Integration with LiveComponents - Validate LiveComponent data
  • HTML5 Attribute Support - Automatically reads validation rules from HTML attributes

Quick Start

Basic Usage

import { Validator } from './modules/validation/index.js';

// Create validator with schema
const validator = Validator.create({
    email: ['required', 'email'],
    age: [
        'required',
        'number',
        { rule: 'min', options: { value: 18 } },
        { rule: 'max', options: { value: 100 } }
    ],
    password: [
        'required',
        { rule: 'minLength', options: { value: 8 } }
    ]
});

// Validate data
const result = await validator.validate({
    email: 'user@example.com',
    age: 25,
    password: 'secret123'
});

if (result.valid) {
    console.log('Validation passed');
} else {
    console.log('Validation errors:', result.errors);
}

From HTML Form

import { Validator } from './modules/validation/index.js';

// Create validator from form element
const form = document.querySelector('#my-form');
const validator = Validator.fromForm(form);

// Validate form data
const formData = new FormData(form);
const data = Object.fromEntries(formData);
const result = await validator.validate(data);

API Reference

Validator.create(schema)

Create a new Validator instance with a schema.

Parameters:

  • schema - Validation schema object

Example:

const validator = Validator.create({
    email: 'email',
    age: ['required', 'number', { rule: 'min', options: { value: 18 } }]
});

Validator.fromForm(form)

Create a validator from an HTML form element, reading validation rules from HTML attributes.

Parameters:

  • form - HTMLFormElement

Example:

<form id="my-form">
    <input type="email" name="email" required />
    <input type="number" name="age" min="18" max="100" required />
    <input type="password" name="password" minlength="8" required />
</form>
const form = document.querySelector('#my-form');
const validator = Validator.fromForm(form);

validator.validate(data)

Validate entire data object against schema.

Parameters:

  • data - Data object to validate

Returns: Promise<ValidationResults>

Example:

const result = await validator.validate({
    email: 'user@example.com',
    age: 25
});

console.log(result.valid); // true or false
console.log(result.errors); // { email: ['...'], age: ['...'] }

validator.validateField(fieldName, value)

Validate a single field.

Parameters:

  • fieldName - Field name
  • value - Field value

Returns: Promise<ValidationResult>

Example:

const result = await validator.validateField('email', 'user@example.com');
console.log(result.valid); // true or false
console.log(result.errors); // ['error message']

validator.validateFields(data, fieldNames)

Validate specific fields.

Parameters:

  • data - Data object
  • fieldNames - Array of field names to validate

Returns: Promise<ValidationResults>

validator.registerRule(name, rule)

Register a custom validation rule.

Parameters:

  • name - Rule name
  • rule - Validation function: (value, options) => boolean | string

Example:

validator.registerRule('customRule', (value, options) => {
    if (value === options.expected) {
        return true;
    }
    return options.message || 'Validation failed';
});

// Use custom rule
const validator = Validator.create({
    field: { rule: 'customRule', options: { expected: 'test', message: 'Must be "test"' } }
});

Built-in Validation Rules

required

Field must have a value.

email: 'required'
// or
email: { rule: 'required', options: { message: 'Email is required' } }

email

Valid email address format.

email: 'email'

url

Valid URL format.

website: 'url'

min / max

Minimum/maximum numeric value.

age: [
    { rule: 'min', options: { value: 18 } },
    { rule: 'max', options: { value: 100 } }
]

minLength / maxLength

Minimum/maximum string length.

password: [
    { rule: 'minLength', options: { value: 8 } },
    { rule: 'maxLength', options: { value: 128 } }
]

pattern

Regex pattern validation.

username: {
    rule: 'pattern',
    options: {
        value: '^[a-zA-Z0-9_]+$',
        message: 'Username can only contain letters, numbers, and underscores'
    }
}

number

Must be a valid number.

price: 'number'

integer

Must be an integer.

quantity: 'integer'

phone

Valid phone number format.

phone: 'phone'

postalCode

Valid postal code (supports DE, US, UK, FR).

postalCode: {
    rule: 'postalCode',
    options: { country: 'DE' }
}

custom

Custom validation function.

field: {
    rule: 'custom',
    options: {
        validator: (value, options) => {
            // Custom validation logic
            return value === options.expected ? true : 'Value must be ' + options.expected;
        },
        expected: 'test'
    }
}

Async Validation

const validator = Validator.create({
    email: {
        rule: 'custom',
        async: true,
        validator: async (value, options) => {
            // Check if email exists via API
            const response = await fetch(`/api/check-email?email=${value}`);
            const data = await response.json();
            
            if (data.exists) {
                return 'Email already exists';
            }
            return true;
        }
    }
});

const result = await validator.validate({ email: 'user@example.com' });

Integration with form-handling

import { Validator } from './modules/validation/index.js';
import { FormHandler } from './modules/form-handling/index.js';

const form = document.querySelector('#my-form');
const validator = Validator.fromForm(form);
const formHandler = FormHandler.create(form);

// Use validator with form handler
formHandler.validator = validator;

Integration with LiveComponents

import { Validator } from './modules/validation/index.js';
import { LiveComponentManager } from './modules/livecomponent/index.js';

const validator = Validator.create({
    email: ['required', 'email'],
    name: ['required', { rule: 'minLength', options: { value: 2 } }]
});

// Validate before action
const lcManager = LiveComponentManager.getInstance();
lcManager.on('action:before-execute', async (componentId, actionName, params) => {
    if (actionName === 'submitForm') {
        const result = await validator.validate(params);
        if (!result.valid) {
            // Handle validation errors
            return false; // Prevent action
        }
    }
});

Use Cases

Form Validation

const validator = Validator.create({
    email: ['required', 'email'],
    password: [
        'required',
        { rule: 'minLength', options: { value: 8 } }
    ],
    confirmPassword: [
        'required',
        {
            rule: 'custom',
            validator: (value, options) => {
                const password = options.password;
                return value === password ? true : 'Passwords do not match';
            },
            options: { password: formData.password }
        }
    ]
});

API Response Validation

const validator = Validator.create({
    id: ['required', 'integer'],
    name: ['required', { rule: 'minLength', options: { value: 1 } }],
    email: ['required', 'email']
});

// Validate API response
const response = await fetch('/api/user');
const data = await response.json();
const result = await validator.validate(data);

if (!result.valid) {
    console.error('Invalid API response:', result.errors);
}

User Input Validation

// Validate on input
const validator = Validator.create({
    search: {
        rule: 'minLength',
        options: { value: 3, message: 'Search must be at least 3 characters' }
    }
});

const input = document.querySelector('#search');
input.addEventListener('input', async (e) => {
    const result = await validator.validateField('search', e.target.value);
    if (!result.valid) {
        showError(result.errors[0]);
    } else {
        hideError();
    }
});

Best Practices

  1. Use Schema-Based Validation - Define validation rules in a schema for reusability
  2. Register Custom Rules - Create reusable custom validation rules
  3. Validate Early - Validate on blur or input for better UX
  4. Show Clear Errors - Display validation errors clearly to users
  5. Use Async Validation Sparingly - Only for necessary checks (e.g., email uniqueness)

Browser Support

  • Chrome/Edge: 90+
  • Firefox: 88+
  • Safari: 14+
  • Mobile: iOS 14+, Android Chrome 90+

Required Features:

  • ES2020 JavaScript
  • Promise support
  • Async/await support

Next: Error Tracking Module