CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-z-schema

JSON schema validator for JavaScript with comprehensive validation capabilities and support for both synchronous and asynchronous validation modes

Overview
Eval results
Files

schema-management.mddocs/

Schema Management

Schema compilation, caching, and remote reference resolution capabilities for handling complex schema relationships and dependencies. z-schema provides comprehensive tools for managing schemas with remote references and inter-schema dependencies.

Capabilities

Remote Reference Management

Set and manage remote schema references for resolving $ref properties.

/**
 * Register a remote schema reference
 * @param uri - URI identifier for the schema
 * @param schema - Schema object or JSON string
 * @param validationOptions - Optional validation options for this schema
 */
setRemoteReference(
    uri: string, 
    schema: any | string, 
    validationOptions?: ZSchema.Options
): void;

Usage Examples:

const ZSchema = require("z-schema");
const validator = new ZSchema();

// Set remote reference from object
const personSchema = {
    type: "object",
    properties: {
        name: { type: "string" },
        age: { type: "number" }
    },
    required: ["name", "age"]
};

validator.setRemoteReference("http://example.com/person", personSchema);

// Set remote reference from JSON string
const addressSchemaJson = JSON.stringify({
    type: "object",
    properties: {
        street: { type: "string" },
        city: { type: "string" },
        zipCode: { type: "string", pattern: "^\\d{5}$" }
    },
    required: ["street", "city"]
});

validator.setRemoteReference("http://example.com/address", addressSchemaJson);

// Use schemas with references
const mainSchema = {
    type: "object",
    properties: {
        person: { $ref: "http://example.com/person" },
        address: { $ref: "http://example.com/address" }
    }
};

// Set with custom validation options
validator.setRemoteReference(
    "http://example.com/strict-schema", 
    strictSchema,
    { strictMode: true, noEmptyStrings: true }
);

const data = {
    person: { name: "John Doe", age: 30 },
    address: { street: "123 Main St", city: "Anytown", zipCode: "12345" }
};

const valid = validator.validate(data, mainSchema);

Global Schema Reader

Set a global function to read schemas synchronously when references are encountered.

/**
 * Set global schema reader function (static method)
 * @param schemaReader - Function that reads schemas by URI
 */
static setSchemaReader(schemaReader: (uri: string) => any): void;

/**
 * Set schema reader function (instance method)
 * @param schemaReader - Function that reads schemas by URI  
 */
setSchemaReader(schemaReader: (uri: string) => any): void;

/**
 * Get current schema reader function
 * @returns Current schema reader function or undefined
 */
getSchemaReader(): ((uri: string) => any) | undefined;

Usage Examples:

const fs = require("fs");
const path = require("path");

// Set global schema reader
ZSchema.setSchemaReader(function(uri) {
    const filename = path.resolve(__dirname, "schemas", uri + ".json");
    try {
        return JSON.parse(fs.readFileSync(filename, "utf8"));
    } catch (error) {
        throw new Error(`Could not read schema: ${uri}`);
    }
});

// Now schemas will be automatically loaded when referenced
const schema = {
    type: "object",
    properties: {
        user: { $ref: "user" }, // Will load from schemas/user.json
        profile: { $ref: "profile" } // Will load from schemas/profile.json
    }
};

const validator = new ZSchema();
const valid = validator.validate(data, schema);

// Instance-specific schema reader
const validator2 = new ZSchema();
validator2.setSchemaReader(function(uri) {
    // Custom loading logic for this validator instance
    return loadSchemaFromDatabase(uri);
});

Schema Resolution

Get fully resolved schemas with all references expanded.

/**
 * Get schema with all references resolved
 * @param schema - Schema to resolve
 * @returns Resolved schema with expanded references
 * @throws Error if resolution fails
 */
getResolvedSchema(schema: any): any;

Usage Examples:

const validator = new ZSchema();

// Set up remote references
validator.setRemoteReference("http://example.com/address", {
    type: "object",
    properties: {
        street: { type: "string" },
        city: { type: "string" }
    }
});

// Schema with references
const schema = {
    type: "object",
    properties: {
        name: { type: "string" },
        address: { $ref: "http://example.com/address" }
    }
};

try {
    const resolvedSchema = validator.getResolvedSchema(schema);
    console.log(JSON.stringify(resolvedSchema, null, 2));
    /* Output:
    {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "address": {
          "type": "object",
          "properties": {
            "street": { "type": "string" },
            "city": { "type": "string" }
          }
        }
      }
    }
    */
} catch (error) {
    console.error("Schema resolution failed:", error.message);
}

Missing Reference Detection

Identify missing remote references that need to be resolved.

/**
 * Get array of missing references from validation errors
 * @param arr - Optional array of errors to check (defaults to last errors)
 * @returns Array of missing reference URIs
 */
getMissingReferences(arr?: any[]): string[];

/**
 * Get array of missing remote references (URLs only)
 * @returns Array of missing remote reference URLs
 */
getMissingRemoteReferences(): string[];

Usage Examples:

const validator = new ZSchema();

const schema = {
    type: "object",
    properties: {
        profile: { $ref: "http://example.com/profile" },
        settings: { $ref: "http://example.com/settings" },
        localRef: { $ref: "#/definitions/local" }
    },
    definitions: {
        local: { type: "string" }
    }
};

const valid = validator.validate({}, schema);

if (!valid) {
    // Get all missing references
    const missingRefs = validator.getMissingReferences();
    console.log("Missing references:", missingRefs);
    // Output: ["http://example.com/profile", "http://example.com/settings"]
    
    // Get only remote (URL) references
    const missingRemote = validator.getMissingRemoteReferences();
    console.log("Missing remote references:", missingRemote);
    // Output: ["http://example.com/profile", "http://example.com/settings"]
    
    // Load missing schemas
    missingRemote.forEach(url => {
        const schema = loadSchemaFromSomewhere(url);
        validator.setRemoteReference(url, schema);
    });
    
    // Retry validation
    const validAfterLoad = validator.validate({}, schema);
}

Automatic Schema Loading

Example implementation of automatic remote schema loading.

// Example helper function for automatic schema loading
function validateWithAutomaticLoading(validator, data, schema, callback) {
    function attemptValidation() {
        const valid = validator.validate(data, schema);
        const missingRefs = validator.getMissingRemoteReferences();
        
        if (missingRefs.length > 0) {
            let loaded = 0;
            const errors = [];
            
            missingRefs.forEach(url => {
                // Load remote schema (example using fetch or http)
                loadRemoteSchema(url)
                    .then(remoteSchema => {
                        validator.setRemoteReference(url, remoteSchema);
                        loaded++;
                        
                        if (loaded === missingRefs.length) {
                            if (errors.length === 0) {
                                attemptValidation(); // Retry
                            } else {
                                callback(errors[0], false);
                            }
                        }
                    })
                    .catch(error => {
                        errors.push(error);
                        loaded++;
                        
                        if (loaded === missingRefs.length) {
                            callback(errors[0], false);
                        }
                    });
            });
        } else {
            callback(null, valid);
        }
    }
    
    attemptValidation();
}

Usage Examples:

const https = require("https");

function loadRemoteSchema(url) {
    return new Promise((resolve, reject) => {
        https.get(url, (response) => {
            let data = "";
            response.on("data", chunk => data += chunk);
            response.on("end", () => {
                try {
                    resolve(JSON.parse(data));
                } catch (error) {
                    reject(error);
                }
            });
        }).on("error", reject);
    });
}

const validator = new ZSchema();
const schema = {
    $ref: "https://json-schema.org/draft-04/schema#"
};

validateWithAutomaticLoading(validator, {type: "string"}, schema, (error, valid) => {
    if (error) {
        console.error("Loading failed:", error);
    } else if (valid) {
        console.log("Validation passed");
    } else {
        console.log("Validation failed:", validator.getLastErrors());
    }
});

Configuration Options

Reference Resolution Options

interface ReferenceOptions {
    /** Don't fail on unresolvable remote references (default: false) */
    ignoreUnresolvableReferences?: boolean;
}

Usage Examples:

// Ignore unresolvable references (for testing)
const lenientValidator = new ZSchema({
    ignoreUnresolvableReferences: true
});

const schema = {
    type: "object",
    properties: {
        data: { $ref: "http://unreachable.example.com/schema" }
    }
};

// This will not fail even though the reference cannot be resolved
const valid = lenientValidator.validate({ data: "test" }, schema);

Schema Compilation Process

Understanding the internal schema compilation process for advanced usage.

/**
 * Compile schema without meta-schema validation
 * @param schema - Schema to compile
 * @returns boolean indicating compilation success
 */
compileSchema(schema: any): boolean;

Usage Examples:

const validator = new ZSchema();

// Compile schema array with inter-references
const schemas = [
    {
        id: "base",
        type: "object",
        properties: {
            id: { type: "number" }
        }
    },
    {
        id: "extended", 
        allOf: [
            { $ref: "base" },
            {
                properties: {
                    name: { type: "string" }
                }
            }
        ]
    }
];

// Compile all schemas
const compiled = validator.compileSchema(schemas);
if (compiled) {
    // Use compiled schema for validation
    const valid = validator.validate(
        { id: 1, name: "test" }, 
        schemas.find(s => s.id === "extended")
    );
}

Error Handling for Schema Management

Schema management operations can fail in various ways. Handle errors appropriately.

interface SchemaManagementErrors {
    "UNRESOLVABLE_REFERENCE": "Reference could not be resolved: {0}";
    "SCHEMA_NOT_REACHABLE": "Validator was not able to read schema with uri: {0}";
    "REF_UNRESOLVED": "Reference has not been resolved during compilation: {0}";
    "REMOTE_NOT_VALID": "Remote reference didn't compile successfully: {0}";
}

Usage Examples:

const validator = new ZSchema();

try {
    const resolvedSchema = validator.getResolvedSchema(schemaWithBadRefs);
} catch (error) {
    if (error.name === "z-schema validation error") {
        error.details.forEach(detail => {
            switch (detail.code) {
                case "UNRESOLVABLE_REFERENCE":
                    console.log(`Cannot resolve reference: ${detail.params[0]}`);
                    break;
                case "SCHEMA_NOT_REACHABLE":
                    console.log(`Schema not reachable: ${detail.params[0]}`);
                    break;
                default:
                    console.log(`Schema error: ${detail.message}`);
            }
        });
    }
}

Install with Tessl CLI

npx tessl i tessl/npm-z-schema

docs

error-handling.md

format-validation.md

index.md

schema-management.md

validation.md

tile.json