Schema API Reference
The ZSchema system is a robust data validation and type management framework that provides strong typing, validation, and middleware processing for data flowing through your application.
Core Concepts
ZSchema extends JSON Schema with additional features:
- Schema Tags - Behavior annotations that guide data processing
- Schema Registry - Centralized storage and retrieval of schema definitions
- Tag Processing - Middleware system for automated data handling
- Validation - Comprehensive validation with sync and async support
ZSchema Definition
defineZSchema
Creates a new schema definition with validation rules and behavioral metadata.
import { defineZSchema, ZSchemaTag } from '@zoopflow/core/zschema';
const UserSchema = defineZSchema({
// Unique name for the schema
name: 'User',
// Optional description for documentation
description: 'User account information',
// Behavioral tags for data processing
tags: [ZSchemaTag.PII, ZSchemaTag.SENSITIVE],
// Custom tags when using ZSchemaTag.CUSTOM
customTags: ['audit-required'],
// Validation configuration
validator: {
// JSON Schema definition
schema: {
type: 'object',
properties: {
id: { type: 'string', format: 'uuid' },
email: { type: 'string', format: 'email' },
name: { type: 'string', minLength: 1 },
createdAt: { type: 'string', format: 'date-time' }
},
required: ['id', 'email', 'name'],
additionalProperties: false
},
// Custom validation function (optional)
validateFn: (value) => {
// Additional validation logic
return true;
},
// Custom error message
errorMessage: 'Invalid user data'
},
// Example value for documentation
example: {
id: '123e4567-e89b-12d3-a456-426614174000',
email: 'user@example.com',
name: 'John Doe',
createdAt: '2023-01-01T00:00:00Z'
}
});extendZSchema
Creates a derived schema that extends an existing one with additional properties.
import { extendZSchema } from '@zoopflow/core/zschema';
const AdminUserSchema = extendZSchema(UserSchema, {
name: 'AdminUser',
description: 'Administrator user with extended permissions',
validator: {
schema: {
type: 'object',
properties: {
// Inherits all properties from UserSchema
role: { type: 'string', enum: ['admin', 'superadmin'] },
permissions: {
type: 'array',
items: { type: 'string' }
}
},
required: ['role']
}
},
example: {
id: '123e4567-e89b-12d3-a456-426614174000',
email: 'admin@example.com',
name: 'Admin User',
createdAt: '2023-01-01T00:00:00Z',
role: 'admin',
permissions: ['manage_users', 'view_reports']
}
});Schema Tags
ZSchema tags annotate schemas with behavioral metadata that influences how data is processed, stored, and displayed throughout the system.
| Tag | Description | Effect |
|---|---|---|
SENSITIVE | Security-sensitive data | Encrypted in transit and at rest |
PII | Personally Identifiable Information | Masked in logs and displays |
ENCRYPTED | Encrypted data | Automatically encrypted/decrypted |
LARGE | Large data exceeding normal limits | Special storage handling |
IMMUTABLE | Data that shouldn't be modified | Prevents modification after creation |
CUSTOM | User-defined tags | Custom behavior defined by application |
ASYNC | Requires asynchronous validation | Cannot be validated synchronously |
import { defineZSchema, ZSchemaTag } from '@zoopflow/core/zschema';
// Using multiple tags for complex behaviors
const CreditCardSchema = defineZSchema({
name: 'CreditCard',
tags: [ZSchemaTag.SENSITIVE, ZSchemaTag.PII, ZSchemaTag.ENCRYPTED],
// This data will be automatically encrypted, masked in logs,
// and treated as high-security information
validator: {
// ...
}
});
// Using custom tags
const AuditSchema = defineZSchema({
name: 'AuditRecord',
tags: [ZSchemaTag.IMMUTABLE, ZSchemaTag.CUSTOM],
customTags: ['compliance-required', 'retain-7-years'],
validator: {
// ...
}
});Schema Registry
The registry provides centralized storage and retrieval of schema definitions.
getZSchemaRegistry
Gets the singleton instance of the schema registry.
import { getZSchemaRegistry } from '@zoopflow/core/zschema/registry';
const registry = getZSchemaRegistry();registerType
Registers a schema with the registry.
// Register a schema
registry.registerType(UserSchema);getType
Retrieves a schema by name.
// Get a schema by name
const schema = registry.getType('User');
if (schema) {
console.log(`Found schema: ${schema.name}`);
}getTypesByTag
Finds schemas with a specific tag.
// Get all schemas with the PII tag
const piiSchemas = registry.getTypesByTag(ZSchemaTag.PII);
console.log(`Found ${piiSchemas.length} schemas with PII data`);Additional Registry Methods
// Check if a schema exists
const exists = registry.hasType('User');
// Get all registered schemas
const allSchemas = registry.getAllTypes();
// Update an existing schema
registry.updateType(updatedUserSchema);
// Remove a schema
registry.unregisterType('DeprecatedSchema');Validation
The ZSchemaValidator provides comprehensive validation capabilities.
ZSchemaValidator
Creates a validator instance for schema validation.
import { ZSchemaValidator } from '@zoopflow/core/zschema';
// Create a validator with default options
const validator = new ZSchemaValidator();
// With custom options
const validatorWithOptions = new ZSchemaValidator({
abortEarly: true,
detailedErrors: true,
formats: {
zipCode: /^\d{5}(-\d{4})?$/
}
});validate
Validates a value against a schema (supports async validation).
// Validate a value against a schema
try {
const result = await validator.validate(UserSchema, userData);
if (result.valid) {
// Use the validated data (typed as User)
const user = result.data;
console.log(`Valid user: ${user.name}`);
} else {
// Handle validation errors
console.error('Validation errors:', result.errors);
}
} catch (error) {
// Handle unexpected errors
console.error('Validation failed:', error);
}validateSync
Synchronously validates a value (throws if schema has async validation).
// Synchronous validation (when performance is critical)
try {
const result = validator.validateSync(UserSchema, userData);
if (result.valid) {
// Use the validated data
const user = result.data;
console.log(`Valid user: ${user.name}`);
}
} catch (error) {
// Handle errors
console.error('Validation failed:', error);
}validateMany
Validates multiple schema-value pairs in parallel.
// Validate multiple values in parallel
const items = [
{ schema: UserSchema, value: userData },
{ schema: ProductSchema, value: productData }
];
const results = await validator.validateMany(items);
const allValid = results.every(result => result.valid);Custom Validators
Register custom validators for complex validation rules.
// Register a synchronous validator
validator.registerValidator('isValidEmail', (value) => {
if (typeof value !== 'string') return false;
return /^[^@]+@[^@]+\.[^@]+$/.test(value);
});
// Register an asynchronous validator
validator.registerValidator('userExists', async (userId) => {
// Check against a database or external service
const user = await userService.findById(userId);
return !!user;
});
// Register a custom format
validator.registerFormat('zipCode', /^\d{5}(-\d{4})?$/);Tag Processing Middleware
The tag processing middleware automatically processes data based on schema tags.
getTagProcessingMiddleware
Gets the singleton middleware instance.
import { getTagProcessingMiddleware } from '@zoopflow/core/zschema/middleware';
const middleware = getTagProcessingMiddleware({
enableCache: true,
maxCacheSize: 1000,
logFn: (message, data) => console.log(message, data)
});processForWrite / processForRead
Process data based on schema tags.
// Process data for storage (encrypts sensitive data, etc.)
const processedForStorage = await middleware.processForWrite(userData, 'User');
// Process data for retrieval (decrypts data, etc.)
const processedForDisplay = await middleware.processForRead(storedData, 'User');Tag Handlers
Register custom tag handlers for special data processing.
import { TagProcessingDirection } from '@zoopflow/core/zschema/middleware';
// Create a custom tag handler
const auditHandler = {
tag: 'audit-required',
// Determine if this handler can process this value
canProcess: (value, context) => {
return typeof value === 'object' && value !== null;
},
// Process the value based on direction
process: async (value, context, direction) => {
if (direction === TagProcessingDirection.WRITE) {
// Add audit information before storing
return {
modified: true,
value: {
...value,
_audit: {
timestamp: new Date().toISOString(),
user: getCurrentUser()
}
}
};
}
// No changes needed when reading
return { modified: false, value };
}
};
// Register the handler
middleware.registerHandler(auditHandler);Validation Types
The ZSchema system includes several validation types:
ZSchemaValidationResult
The result of validation.
interface ZSchemaValidationResult<T> {
// Whether validation was successful
valid: boolean;
// Validation errors (null if valid)
errors: string[] | null;
// Detailed error information (if enabled)
errorDetails?: ValidationErrorDetail[] | null;
// The validated data (typed as T if valid, null if invalid)
data: T | null;
}ZSchemaValidationError
Error thrown when validation fails and throwOnError is enabled.
class ZSchemaValidationError extends Error {
// Error message
message: string;
// Array of validation error messages
errors: string[];
// Name of the schema that failed validation
schemaName: string;
// Detailed error information (if enabled)
errorDetails?: ValidationErrorDetail[];
}ValidationOptions
Options for validation.
interface ZSchemaValidationOptions {
// Stop at first error (default: false)
abortEarly?: boolean;
// Include detailed error information (default: false)
detailedErrors?: boolean;
// Throw error on validation failure (default: false)
throwOnError?: boolean;
// Custom formats for validation
formats?: Record<string, RegExp>;
}Best Practices
-
Namespace Schema Names
Use domain prefixes to avoid name collisions:User.Account,Product.Catalog. -
Reuse Common Schemas
Define base schemas for common patterns and extend them for specific needs. -
Tag Data Appropriately
Apply tags consistently to ensure proper handling of sensitive data. -
Provide Examples
Include realistic examples in schema definitions for documentation. -
Error Messages
Use descriptive error messages to help users understand validation failures. -
Custom Validators
Use custom validators for complex business rules that can't be expressed in JSON Schema. -
Schema Registry
Register all schemas with the registry for centralized management. -
Validation Context
Pass context to validation functions for contextual validation rules.
Example: Complete Schema System
Here's a comprehensive example showing the ZSchema system in use:
import {
defineZSchema,
ZSchemaTag,
ZSchemaValidator,
getZSchemaRegistry,
getTagProcessingMiddleware
} from '@zoopflow/core/zschema';
// 1. Define schemas
const AddressSchema = defineZSchema({
name: 'Address',
tags: [ZSchemaTag.PII],
validator: {
schema: {
type: 'object',
properties: {
street: { type: 'string' },
city: { type: 'string' },
state: { type: 'string' },
zipCode: { type: 'string', pattern: '\\d{5}(-\\d{4})?' },
country: { type: 'string' }
},
required: ['street', 'city', 'state', 'zipCode']
}
}
});
const UserSchema = defineZSchema({
name: 'User',
tags: [ZSchemaTag.PII, ZSchemaTag.SENSITIVE],
validator: {
schema: {
type: 'object',
properties: {
id: { type: 'string', format: 'uuid' },
email: { type: 'string', format: 'email' },
name: { type: 'string' },
address: { $ref: '#/definitions/Address' },
createdAt: { type: 'string', format: 'date-time' }
},
required: ['id', 'email', 'name'],
definitions: {
Address: AddressSchema.validator.schema
}
},
validateFn: (value) => {
// Custom domain validation
if (value.email && value.email.endsWith('example.com')) {
return false; // Reject example.com emails
}
return true;
},
errorMessage: 'Invalid user data'
}
});
// 2. Register schemas
const registry = getZSchemaRegistry();
registry.registerType(AddressSchema);
registry.registerType(UserSchema);
// 3. Create validator
const validator = new ZSchemaValidator({
detailedErrors: true,
formats: {
zipCode: /^\d{5}(-\d{4})?$/
}
});
// 4. Set up tag processing
const middleware = getTagProcessingMiddleware();
// 5. Using the schema system
async function processUserData(inputData) {
try {
// Validate the input
const result = await validator.validate(UserSchema, inputData);
if (!result.valid) {
console.error('Validation errors:', result.errors);
return { success: false, errors: result.errors };
}
// At this point, result.data is typed as User
const user = result.data;
// Process for storage (encrypt sensitive fields, etc.)
const processedData = await middleware.processForWrite(user, 'User');
// Store the processed data
// ...
// When retrieving, process for reading
const retrievedData = processedData; // In reality, this would come from storage
const displayData = await middleware.processForRead(retrievedData, 'User');
return {
success: true,
data: displayData
};
} catch (error) {
console.error('Processing error:', error);
return {
success: false,
errors: [error.message]
};
}
}