ExJsonschema (ExJsonschema v0.1.17)

View Source

High-performance JSON Schema validation for Elixir using Rust.

Fast, spec-compliant JSON Schema validation powered by the Rust jsonschema crate with support for multiple draft versions and comprehensive error reporting.

Quick Start

# Compile and validate
schema = ~s({"type": "object", "properties": {"name": {"type": "string"}}})
{:ok, validator} = ExJsonschema.compile(schema)
:ok = ExJsonschema.validate(validator, ~s({"name": "John"}))

# Get detailed errors
{:error, errors} = ExJsonschema.validate(validator, ~s({"name": 123}))
ExJsonschema.format_errors(errors, :human)

Core Functions

  • compile/1,2 - Compile JSON Schema for validation
  • validate/2,3 - Validate JSON against compiled schema
  • valid?/2,3 - Quick boolean validation check
  • meta_validate/1 - Validate schema document itself
  • format_errors/3 - Format validation errors for display
  • analyze_errors/1,2 - Analyze error patterns and severity

Output Formats

  • :basic - Simple pass/fail (fastest)
  • :detailed - Structured errors with paths (default)
  • :verbose - Comprehensive errors with context and suggestions

Configuration & Options

# Use predefined profiles for common scenarios
strict_opts = ExJsonschema.Options.new(:strict)      # API validation
lenient_opts = ExJsonschema.Options.new(:lenient)    # User forms
perf_opts = ExJsonschema.Options.new(:performance)   # High-volume

# Enable validation options
ExJsonschema.validate(validator, json, validate_formats: true)
ExJsonschema.valid?(validator, json, stop_on_first_error: true)

Draft Support & Meta-Validation

Supports JSON Schema drafts 4, 6, 7, 2019-09, and 2020-12:

ExJsonschema.compile_draft7(schema)        # Draft-specific compilation
ExJsonschema.compile_auto_draft(schema)    # Auto-detect from $schema

# Validate schema documents against meta-schemas
ExJsonschema.meta_valid?(schema)           # Quick check
ExJsonschema.meta_validate(schema)         # Detailed errors

Error Handling & Analysis

Rich error formatting and intelligent analysis:

{:error, errors} = ExJsonschema.validate(validator, invalid_data)

# Format for display
ExJsonschema.format_errors(errors, :human, color: true)
ExJsonschema.format_errors(errors, :json, pretty: true)
ExJsonschema.format_errors(errors, :table, compact: true)

# Analyze patterns and get recommendations
analysis = ExJsonschema.analyze_errors(errors)
analysis.total_errors        # => 5
analysis.categories          # => %{type_mismatch: 2, constraint_violation: 3}
analysis.recommendations     # => ["Review required fields...", ...]

Comprehensive Documentation

For detailed guides, examples, and advanced usage:

  • HexDocs - Complete API reference
  • GitHub - Source code and examples
  • docs/guides/ - In-depth usage guides and integration patterns

Built on the blazing-fast Rust jsonschema crate for optimal performance.

Summary

Types

Result of basic validation operations.

A compiled JSON Schema validator optimized for repeated use.

A JSON document represented as a string.

Result of validation operations.

Functions

Analyzes validation errors to provide insights, categorization, and recommendations.

Compiles a JSON Schema string into an optimized validator.

Compiles a JSON Schema string with options into an optimized validator.

Compiles a JSON Schema, raising an exception on failure.

Compiles a schema using the automatically detected draft version.

Compiles a JSON Schema using Draft 4 specific optimizations.

Compiles a JSON Schema using Draft 6 specific optimizations.

Compiles a JSON Schema using Draft 7 specific optimizations.

Compiles a JSON Schema using Draft 2019-09 specific optimizations.

Compiles a JSON Schema using Draft 2020-12 specific optimizations.

Detects the JSON Schema draft version from a schema document.

Formats validation errors for display using the specified format.

Checks if a JSON Schema document is valid against its meta-schema.

Validates a JSON Schema document against its meta-schema.

Validates a JSON Schema document against its meta-schema, raising on error.

Returns all supported JSON Schema draft versions.

Checks if JSON is valid against a compiled schema without returning error details.

Checks if JSON is valid against a compiled schema with validation options.

Validates JSON against a compiled schema.

Validates JSON against a compiled schema with output format and validation options control.

Validates JSON against a compiled schema, raising an exception on validation failure.

One-shot validation: compiles schema and validates instance in a single call.

Types

basic_validation_result()

@type basic_validation_result() :: :ok | {:error, :validation_failed}

Result of basic validation operations.

  • :ok - Validation succeeded
  • {:error, :validation_failed} - Validation failed (no detailed errors)

This is returned by validation with output: :basic for fastest performance when you only need to know if validation passed or failed.

compiled_schema()

@type compiled_schema() :: reference()

A compiled JSON Schema validator optimized for repeated use.

This is an opaque reference to a compiled schema stored in the Rust NIF. Compile once with compile/1 or compile/2, then use multiple times with validate/2, validate/3, or valid?/2, valid?/3.

Performance Note

Compiled schemas are significantly faster than one-shot validation when validating multiple instances against the same schema.

json_string()

@type json_string() :: String.t()

A JSON document represented as a string.

Must be valid JSON syntax. Both the schema and instance documents are expected to be JSON strings that will be parsed by the Rust NIF.

Examples

"{\"type\": \"string\"}"
"{\"name\": \"John\", \"age\": 30}"
"[\"item1\", \"item2\", \"item3\"]"

validation_result()

@type validation_result() :: :ok | {:error, [ExJsonschema.ValidationError.t()]}

Result of validation operations.

  • :ok - Validation succeeded, the instance is valid
  • {:error, [ValidationError.t()]} - Validation failed with detailed error information

The error list contains structured error information including:

  • Instance path (where the error occurred)
  • Schema path (which schema rule failed)
  • Descriptive error message
  • Additional context in verbose mode

Functions

analyze_errors(errors, format \\ :analysis)

@spec analyze_errors([ExJsonschema.ValidationError.t()], :summary) :: String.t()

Analyzes validation errors to provide insights, categorization, and recommendations.

Returns a comprehensive analysis including error categories, severity levels, detected patterns, and actionable recommendations for fixing the issues.

Examples

{:error, errors} = ExJsonschema.validate(validator, invalid_json)
analysis = ExJsonschema.analyze_errors(errors)

analysis.total_errors
#=> 3

analysis.categories
#=> %{type_mismatch: 1, constraint_violation: 2}

analysis.recommendations
#=> ["Review required fields - ensure all mandatory properties are included", ...]

# Get human-readable summary
ExJsonschema.analyze_errors(errors, :summary)
#=> "3 validation errors detected\n\nCategories: 1 type mismatches, 2 constraint violations..."

compile(schema_json)

@spec compile(json_string()) ::
  {:ok, compiled_schema()} | {:error, ExJsonschema.CompilationError.t()}

Compiles a JSON Schema string into an optimized validator.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema)
iex> is_reference(compiled)
true

iex> invalid_schema = ~s({"type": "invalid_type"})
iex> {:error, %ExJsonschema.CompilationError{type: :compilation_error}} = ExJsonschema.compile(invalid_schema)

compile(schema_json, options)

Compiles a JSON Schema string with options into an optimized validator.

Options

Accepts either an ExJsonschema.Options struct or keyword list of options. When using :auto draft detection, the $schema property in the schema will be examined to determine the appropriate JSON Schema draft version.

Examples

# With Options struct
iex> opts = ExJsonschema.Options.new(draft: :draft7, validate_formats: true)
iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema, opts)
iex> is_reference(compiled)
true

# With keyword list
iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema, draft: :auto)
iex> is_reference(compiled)
true

# Automatic draft detection
iex> schema_with_draft = ~s({"$schema": "http://json-schema.org/draft-07/schema#", "type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema_with_draft, draft: :auto)
iex> is_reference(compiled)
true

compile!(schema_json)

@spec compile!(json_string()) :: compiled_schema()

Compiles a JSON Schema, raising an exception on failure.

Examples

iex> schema = ~s({"type": "string"})
iex> compiled = ExJsonschema.compile!(schema)
iex> is_reference(compiled)
true

compile_auto_draft(schema_json, options \\ [])

@spec compile_auto_draft(
  json_string(),
  keyword()
) :: {:ok, compiled_schema()} | {:error, ExJsonschema.CompilationError.t()}

Compiles a schema using the automatically detected draft version.

This is a convenience function that combines detect_draft/1 and compile/2 to automatically select the most appropriate draft for the schema.

Examples

# Schema with explicit $schema
iex> schema = ~s({"$schema": "http://json-schema.org/draft-07/schema#", "type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile_auto_draft(schema)
iex> is_reference(compiled)
true

# Schema without $schema (defaults to latest)
iex> schema = ~s({"type": "number"})
iex> {:ok, compiled} = ExJsonschema.compile_auto_draft(schema)
iex> is_reference(compiled)
true

compile_draft4(schema_json, options \\ [])

@spec compile_draft4(
  json_string(),
  keyword()
) :: {:ok, compiled_schema()} | {:error, ExJsonschema.CompilationError.t()}

Compiles a JSON Schema using Draft 4 specific optimizations.

This provides a direct shortcut to compile schemas specifically for Draft 4, which can be faster than using the generic compile/2 with draft options.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile_draft4(schema)
iex> is_reference(compiled)
true

# With additional options
iex> {:ok, compiled} = ExJsonschema.compile_draft4(schema, validate_formats: true)
iex> is_reference(compiled)
true

compile_draft6(schema_json, options \\ [])

@spec compile_draft6(
  json_string(),
  keyword()
) :: {:ok, compiled_schema()} | {:error, ExJsonschema.CompilationError.t()}

Compiles a JSON Schema using Draft 6 specific optimizations.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile_draft6(schema)
iex> is_reference(compiled)
true

compile_draft7(schema_json, options \\ [])

@spec compile_draft7(
  json_string(),
  keyword()
) :: {:ok, compiled_schema()} | {:error, ExJsonschema.CompilationError.t()}

Compiles a JSON Schema using Draft 7 specific optimizations.

Draft 7 is widely used and includes support for conditional schemas with if, then, else.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile_draft7(schema)
iex> is_reference(compiled)
true

compile_draft201909(schema_json, options \\ [])

@spec compile_draft201909(
  json_string(),
  keyword()
) :: {:ok, compiled_schema()} | {:error, ExJsonschema.CompilationError.t()}

Compiles a JSON Schema using Draft 2019-09 specific optimizations.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile_draft201909(schema)
iex> is_reference(compiled)
true

compile_draft202012(schema_json, options \\ [])

@spec compile_draft202012(
  json_string(),
  keyword()
) :: {:ok, compiled_schema()} | {:error, ExJsonschema.CompilationError.t()}

Compiles a JSON Schema using Draft 2020-12 specific optimizations.

Draft 2020-12 is the latest specification with the most comprehensive feature set.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile_draft202012(schema)
iex> is_reference(compiled)
true

detect_draft(schema)

@spec detect_draft(json_string() | map()) ::
  {:ok, ExJsonschema.Options.draft()} | {:error, String.t()}

Detects the JSON Schema draft version from a schema document.

This function examines the $schema property to determine which JSON Schema draft version the schema is written for. If no $schema is present or the URL is unrecognized, it returns the default draft (2020-12).

Examples

# Schema with explicit draft
iex> schema = ~s({"$schema": "http://json-schema.org/draft-07/schema#", "type": "string"})
iex> ExJsonschema.detect_draft(schema)
{:ok, :draft7}

# Schema without $schema (uses default)
iex> schema = ~s({"type": "number"})
iex> ExJsonschema.detect_draft(schema)
{:ok, :draft202012}

# Map input
iex> schema = %{"$schema" => "https://json-schema.org/draft/2020-12/schema", "type" => "object"}
iex> ExJsonschema.detect_draft(schema)
{:ok, :draft202012}

format_errors(errors, format, options \\ [])

Formats validation errors for display using the specified format.

This is a convenience function that delegates to ExJsonschema.ErrorFormatter.format/3.

Supported Formats

  • :human - Human-readable text format with colors and suggestions
  • :json - Structured JSON format for programmatic use
  • :table - Tabular format for easy scanning of multiple errors
  • :markdown - Markdown format for documentation and web display
  • :llm - LLM-optimized format for AI assistant consumption

Examples

# Format errors for human consumption
ExJsonschema.format_errors(errors, :human)

# Format as pretty-printed JSON
ExJsonschema.format_errors(errors, :json, pretty: true)

# Format as compact table
ExJsonschema.format_errors(errors, :table, compact: true)

meta_valid?(schema_json)

@spec meta_valid?(binary()) :: boolean()

Checks if a JSON Schema document is valid against its meta-schema.

This function validates that the provided schema document itself follows the correct JSON Schema specification for its draft version.

Examples

iex> schema = ~s({"type": "string", "minLength": 5})
iex> ExJsonschema.meta_valid?(schema)
true

iex> invalid_schema = ~s({"type": "invalid_type"})
iex> ExJsonschema.meta_valid?(invalid_schema)
false

Parameters

  • schema_json - JSON string containing the schema to validate

Returns

  • true if the schema is valid against its meta-schema
  • false if the schema is invalid
  • Raises ArgumentError if JSON is malformed

meta_validate(schema_json)

@spec meta_validate(binary()) ::
  :ok | {:error, [ExJsonschema.ValidationError.t()]} | {:error, binary()}

Validates a JSON Schema document against its meta-schema.

Returns detailed validation errors compatible with standard validation error formatting and analysis tools.

Examples

iex> schema = ~s({"type": "string", "minLength": 5})
iex> ExJsonschema.meta_validate(schema)
:ok

iex> invalid_schema = ~s({"type": "invalid_type"})
iex> {:error, errors} = ExJsonschema.meta_validate(invalid_schema)
iex> ExJsonschema.format_errors(errors, :human)

Parameters

  • schema_json - JSON string containing the schema to validate

Returns

  • :ok if the schema is valid
  • {:error, [ExJsonschema.ValidationError.t()]} if validation fails
  • {:error, reason} if JSON parsing fails

meta_validate!(schema_json)

@spec meta_validate!(binary()) :: :ok

Validates a JSON Schema document against its meta-schema, raising on error.

Like meta_validate/1 but raises ExJsonschema.ValidationError if validation fails.

Examples

iex> schema = ~s({"type": "string", "minLength": 5})
iex> ExJsonschema.meta_validate!(schema)
:ok

Parameters

  • schema_json - JSON string containing the schema to validate

Returns

supported_drafts()

@spec supported_drafts() :: [ExJsonschema.Options.draft()]

Returns all supported JSON Schema draft versions.

Examples

iex> drafts = ExJsonschema.supported_drafts()
iex> :draft7 in drafts
true
iex> :draft202012 in drafts
true

valid?(compiled_schema, instance_json)

@spec valid?(compiled_schema(), json_string()) :: boolean()

Checks if JSON is valid against a compiled schema without returning error details.

This is faster than validate/2 when you only need to know if the JSON is valid.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema)
iex> ExJsonschema.valid?(compiled, ~s("hello"))
true
iex> ExJsonschema.valid?(compiled, ~s(123))
false

valid?(compiled_schema, instance_json, options)

Checks if JSON is valid against a compiled schema with validation options.

This is faster than validate/3 when you only need to know if the JSON is valid and supports validation options like format validation.

Validation Options

  • validate_formats: boolean() - Enable format validation (default: false)
  • ignore_unknown_formats: boolean() - Ignore unknown format assertions (default: true)
  • stop_on_first_error: boolean() - Stop validation on first error (default: false)
  • collect_annotations: boolean() - Collect annotations during validation (default: true)

Examples

iex> schema = ~s({"type": "string", "format": "email"})
iex> {:ok, compiled} = ExJsonschema.compile(schema)
iex> ExJsonschema.valid?(compiled, ~s("test@example.com"), validate_formats: true)
true
iex> ExJsonschema.valid?(compiled, ~s("not-email"), validate_formats: true)
false

validate(compiled_schema, instance_json)

@spec validate(compiled_schema(), json_string()) :: validation_result()

Validates JSON against a compiled schema.

Returns :ok if valid, or {:error, errors} with detailed error information.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema)
iex> ExJsonschema.validate(compiled, ~s("hello"))
:ok
iex> match?({:error, [%ExJsonschema.ValidationError{} | _]}, ExJsonschema.validate(compiled, ~s(123)))
true

validate(compiled_schema, instance_json, options)

Validates JSON against a compiled schema with output format and validation options control.

Output Formats

  • :basic - Returns :ok or {:error, :validation_failed} (fastest)
  • :detailed - Returns :ok or {:error, [ValidationError.t()]} (default)
  • :verbose - Returns detailed errors with additional context, values, and suggestions

Validation Options

  • output: :basic | :detailed | :verbose - Controls error output format (default: :detailed)

Note: Validation behavior options like validate_formats, stop_on_first_error, etc. must be set during schema compilation, not at validation time. Use ExJsonschema.compile/2 with appropriate options to control validation behavior.

Examples

# Basic format (fastest)
iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema)
iex> ExJsonschema.validate(compiled, ~s("hello"), output: :basic)
:ok
iex> ExJsonschema.validate(compiled, ~s(123), output: :basic)
{:error, :validation_failed}

# Detailed format (default)
iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema)
iex> ExJsonschema.validate(compiled, ~s(123), output: :detailed)
{:error, [%ExJsonschema.ValidationError{}]}

# Note: For format validation, set during compilation:
# schema = ~s({"type": "string", "format": "email"})
# {:ok, compiled} = ExJsonschema.compile(schema, validate_formats: true)
# ExJsonschema.validate(compiled, ~s("not-email"))  # Now validates formats

validate!(compiled_schema, instance_json)

@spec validate!(compiled_schema(), json_string()) :: :ok

Validates JSON against a compiled schema, raising an exception on validation failure.

Examples

iex> schema = ~s({"type": "string"})
iex> {:ok, compiled} = ExJsonschema.compile(schema)
iex> ExJsonschema.validate!(compiled, ~s("hello"))
:ok

validate_once(schema_json, instance_json)

@spec validate_once(json_string(), json_string()) ::
  validation_result() | {:error, ExJsonschema.CompilationError.t()}

One-shot validation: compiles schema and validates instance in a single call.

This is convenient for one-time validations but less efficient for repeated validations of the same schema.

Examples

iex> schema = ~s({"type": "string"})
iex> ExJsonschema.validate_once(schema, ~s("hello"))
:ok
iex> match?({:error, [%ExJsonschema.ValidationError{} | _]}, ExJsonschema.validate_once(schema, ~s(123)))
true