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
- 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
463 lines
9.6 KiB
Markdown
463 lines
9.6 KiB
Markdown
# 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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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**:
|
|
```javascript
|
|
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**:
|
|
```html
|
|
<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>
|
|
```
|
|
|
|
```javascript
|
|
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**:
|
|
```javascript
|
|
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**:
|
|
```javascript
|
|
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**:
|
|
```javascript
|
|
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.
|
|
|
|
```javascript
|
|
email: 'required'
|
|
// or
|
|
email: { rule: 'required', options: { message: 'Email is required' } }
|
|
```
|
|
|
|
### email
|
|
|
|
Valid email address format.
|
|
|
|
```javascript
|
|
email: 'email'
|
|
```
|
|
|
|
### url
|
|
|
|
Valid URL format.
|
|
|
|
```javascript
|
|
website: 'url'
|
|
```
|
|
|
|
### min / max
|
|
|
|
Minimum/maximum numeric value.
|
|
|
|
```javascript
|
|
age: [
|
|
{ rule: 'min', options: { value: 18 } },
|
|
{ rule: 'max', options: { value: 100 } }
|
|
]
|
|
```
|
|
|
|
### minLength / maxLength
|
|
|
|
Minimum/maximum string length.
|
|
|
|
```javascript
|
|
password: [
|
|
{ rule: 'minLength', options: { value: 8 } },
|
|
{ rule: 'maxLength', options: { value: 128 } }
|
|
]
|
|
```
|
|
|
|
### pattern
|
|
|
|
Regex pattern validation.
|
|
|
|
```javascript
|
|
username: {
|
|
rule: 'pattern',
|
|
options: {
|
|
value: '^[a-zA-Z0-9_]+$',
|
|
message: 'Username can only contain letters, numbers, and underscores'
|
|
}
|
|
}
|
|
```
|
|
|
|
### number
|
|
|
|
Must be a valid number.
|
|
|
|
```javascript
|
|
price: 'number'
|
|
```
|
|
|
|
### integer
|
|
|
|
Must be an integer.
|
|
|
|
```javascript
|
|
quantity: 'integer'
|
|
```
|
|
|
|
### phone
|
|
|
|
Valid phone number format.
|
|
|
|
```javascript
|
|
phone: 'phone'
|
|
```
|
|
|
|
### postalCode
|
|
|
|
Valid postal code (supports DE, US, UK, FR).
|
|
|
|
```javascript
|
|
postalCode: {
|
|
rule: 'postalCode',
|
|
options: { country: 'DE' }
|
|
}
|
|
```
|
|
|
|
### custom
|
|
|
|
Custom validation function.
|
|
|
|
```javascript
|
|
field: {
|
|
rule: 'custom',
|
|
options: {
|
|
validator: (value, options) => {
|
|
// Custom validation logic
|
|
return value === options.expected ? true : 'Value must be ' + options.expected;
|
|
},
|
|
expected: 'test'
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Async Validation
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
// 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](error-tracking.md) →
|
|
|