Skip to content

Feature: JSON Schema Integration with Optional Dependencies #51

@Goldziher

Description

@Goldziher

Feature: JSON Schema Integration with Optional Dependencies

Add support for automatically creating factories from JSON Schema definitions. This would enable factory generation from OpenAPI/Swagger specifications and support legacy systems using JSON Schema.

Implementation Requirements

  1. Subclass the Base Factory

    • Create a JsonSchemaFactory class that extends the base Factory class
    • Follow the same pattern as ZodFactory for consistency
    • Override necessary methods like build() and batch()
  2. Use AJV for Schema Validation

    • Use AJV (Another JSON Schema Validator) to avoid reinventing the wheel
    • Validate that the JSON Schema is parsable and valid
    • Support JSON Schema draft-07 and later versions
    • Leverage AJV's extensive validation capabilities
  3. Generate Mock Data from JSON Schema

    • Similar to ZodFactory, automatically generate mock data based on the JSON Schema
    • Support all JSON Schema types and formats
    • Handle schema composition (allOf, anyOf, oneOf)
    • Respect constraints (minLength, maxLength, minimum, maximum, etc.)

Technical Architecture

import { Factory } from 'interface-forge';
import Ajv from 'ajv';
import type { JSONSchema7 } from 'json-schema';

export class JsonSchemaFactory<T> extends Factory<T> {
  private ajv: Ajv;
  private schema: JSONSchema7;
  
  constructor(schema: JSONSchema7, options?: FactoryOptions) {
    // Validate schema with AJV
    const ajv = new Ajv();
    const valid = ajv.validateSchema(schema);
    if (\!valid) {
      throw new Error(`Invalid JSON Schema: ${ajv.errorsText()}`);
    }
    
    // Create factory function that generates data from schema
    const factoryFn = (faker) => generateFromSchema(schema, faker);
    
    super(factoryFn, options);
    this.ajv = ajv;
    this.schema = schema;
  }
  
  // Override build to add validation
  build(overrides?: Partial<T>): T {
    const data = super.build(overrides);
    const valid = this.ajv.validate(this.schema, data);
    if (\!valid) {
      throw new Error(`Generated data does not match schema: ${this.ajv.errorsText()}`);
    }
    return data;
  }
}

Key Features

  • Schema Validation: Use AJV to validate both the schema itself and generated data
  • Type Mapping: Map JSON Schema types to appropriate Faker.js methods
  • Constraint Handling: Respect all JSON Schema constraints
  • Format Support: Handle standard formats (email, uri, date-time, etc.)
  • Composition Support: Handle allOf, anyOf, oneOf, and $ref
  • Optional Dependency: Implement as interface-forge/json-schema

Example Usage

import { JsonSchemaFactory } from 'interface-forge/json-schema';

const schema = {
  type: 'object',
  properties: {
    id: { type: 'string', format: 'uuid' },
    name: { type: 'string', minLength: 1, maxLength: 50 },
    age: { type: 'integer', minimum: 0, maximum: 120 },
    email: { type: 'string', format: 'email' },
    tags: { 
      type: 'array', 
      items: { type: 'string' },
      minItems: 1,
      maxItems: 5
    }
  },
  required: ['id', 'name', 'email']
};

const factory = new JsonSchemaFactory(schema);
const user = factory.build();
// Generates valid data according to schema

// With overrides
const admin = factory.build({ role: 'admin' });

// Batch generation
const users = factory.batch(10);

JSON Schema Feature Support

The factory should support:

  • Basic Types: string, number, integer, boolean, null, array, object
  • String Formats: date-time, date, time, email, uri, uuid, regex, etc.
  • String Constraints: minLength, maxLength, pattern
  • Number Constraints: minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf
  • Array Constraints: minItems, maxItems, uniqueItems
  • Object Constraints: minProperties, maxProperties, required, dependencies
  • Composition: allOf, anyOf, oneOf, not
  • References: $ref support for schema reuse
  • Conditional: if/then/else schemas

Type Generation Examples

// String with format
{ type: 'string', format: 'email' }  faker.internet.email()

// Number with constraints  
{ type: 'integer', minimum: 18, maximum: 65 }  faker.number.int({ min: 18, max: 65 })

// Array with constraints
{ 
  type: 'array', 
  items: { type: 'string' },
  minItems: 2,
  maxItems: 5
}  faker.helpers.multiple(() => faker.string.sample(), { count: { min: 2, max: 5 } })

// Pattern matching
{ type: 'string', pattern: '^[A-Z]{3}-\\d{4}$' }  faker.helpers.fromRegExp(/^[A-Z]{3}-\d{4}$/)

Integration with AJV

// Advanced AJV configuration
const factory = new JsonSchemaFactory(schema, {
  ajvOptions: {
    allErrors: true,
    verbose: true,
    strict: true
  },
  // Custom format generators
  formats: {
    'custom-id': (faker) => `ID-${faker.string.numeric(6)}`
  },
  // Validation behavior
  validateOutput: true, // Validate generated data
  coerceTypes: true    // Coerce types if needed
});

Testing Requirements

  • Comprehensive test suite similar to ZodFactory
  • Test all JSON Schema types and constraints
  • Validate AJV integration works correctly
  • Performance benchmarks for large schemas
  • Edge case testing (circular refs, deep nesting)
  • Ensure generated data always passes schema validation

Dependencies

  • ajv as peer dependency for JSON Schema validation
  • json-schema types for TypeScript support
  • Follow the same optional dependency pattern as Zod integration

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestgood first issueGood for newcomershelp wantedExtra attention is neededonlydust-waveContribute to awesome OSS repos during OnlyDust's open source week

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions