Current section
Files
Jump to
Current section
Files
lib/ex_jsonschema.ex
defmodule ExJsonschema do
@moduledoc """
High-performance JSON Schema validation for Elixir using Rust.
This library provides a fast and spec-compliant JSON Schema validator
powered by the Rust `jsonschema` crate. It supports multiple JSON Schema
draft versions and provides detailed validation error information.
## Quick Start
# Compile a schema
schema = ~s({"type": "object", "properties": {"name": {"type": "string"}}})
{:ok, compiled} = ExJsonschema.compile(schema)
# Validate JSON
valid_json = ~s({"name": "John"})
:ok = ExJsonschema.validate(compiled, valid_json)
invalid_json = ~s({"name": 123})
{:error, errors} = ExJsonschema.validate(compiled, invalid_json)
## Features
- Fast validation using Rust
- Support for JSON Schema draft-07, draft 2019-09, and draft 2020-12
- Detailed error messages with path information
- Precompiled binaries for easy installation
- Zero Rust toolchain required for end users
"""
alias ExJsonschema.{CompilationError, Native, ValidationError}
@type compiled_schema :: reference()
@type json_string :: String.t()
@type validation_result :: :ok | {:error, [ValidationError.t()]}
@doc """
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)
"""
@spec compile(json_string()) :: {:ok, compiled_schema()} | {:error, CompilationError.t()}
def compile(schema_json) when is_binary(schema_json) do
case Native.compile_schema(schema_json) do
{:ok, compiled} -> {:ok, compiled}
{:error, error_map} -> {:error, CompilationError.from_map(error_map)}
end
end
@doc """
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
"""
@spec compile!(json_string()) :: compiled_schema()
def compile!(schema_json) when is_binary(schema_json) do
case compile(schema_json) do
{:ok, compiled} ->
compiled
{:error, %CompilationError{} = error} ->
raise ArgumentError, "Failed to compile schema: #{error}"
end
end
@doc """
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
"""
@spec validate(compiled_schema(), json_string()) :: validation_result()
def validate(compiled_schema, instance_json)
when is_reference(compiled_schema) and is_binary(instance_json) do
case Native.validate_detailed(compiled_schema, instance_json) do
:ok ->
:ok
{:error, error_list} when is_list(error_list) ->
errors = Enum.map(error_list, &ValidationError.from_map/1)
{:error, errors}
{:error, _reason} ->
{:error, [:validation_error]}
end
end
@doc """
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
"""
@spec validate!(compiled_schema(), json_string()) :: :ok
def validate!(compiled_schema, instance_json) do
case validate(compiled_schema, instance_json) do
:ok -> :ok
{:error, errors} -> raise ExJsonschema.ValidationError.Exception, errors: errors
end
end
@doc """
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
"""
@spec valid?(compiled_schema(), json_string()) :: boolean()
def valid?(compiled_schema, instance_json)
when is_reference(compiled_schema) and is_binary(instance_json) do
Native.valid?(compiled_schema, instance_json)
end
@doc """
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
"""
@spec validate_once(json_string(), json_string()) ::
validation_result() | {:error, CompilationError.t()}
def validate_once(schema_json, instance_json) do
with {:ok, compiled} <- compile(schema_json) do
validate(compiled, instance_json)
end
end
end