API Reference
Schema API

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.

TagDescriptionEffect
SENSITIVESecurity-sensitive dataEncrypted in transit and at rest
PIIPersonally Identifiable InformationMasked in logs and displays
ENCRYPTEDEncrypted dataAutomatically encrypted/decrypted
LARGELarge data exceeding normal limitsSpecial storage handling
IMMUTABLEData that shouldn't be modifiedPrevents modification after creation
CUSTOMUser-defined tagsCustom behavior defined by application
ASYNCRequires asynchronous validationCannot 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

  1. Namespace Schema Names
    Use domain prefixes to avoid name collisions: User.Account, Product.Catalog.

  2. Reuse Common Schemas
    Define base schemas for common patterns and extend them for specific needs.

  3. Tag Data Appropriately
    Apply tags consistently to ensure proper handling of sensitive data.

  4. Provide Examples
    Include realistic examples in schema definitions for documentation.

  5. Error Messages
    Use descriptive error messages to help users understand validation failures.

  6. Custom Validators
    Use custom validators for complex business rules that can't be expressed in JSON Schema.

  7. Schema Registry
    Register all schemas with the registry for centralized management.

  8. 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] 
    };
  }
}

Related API References