ExJsonschema
Fast, safe JSON Schema validation for Elixir
ExJsonschema validates JSON against schemas using a battle-tested Rust engine. It's designed to be simple to use while providing the performance and reliability you need for production applications.
Why ExJsonschema?
- Zero Setup - Add to your deps, it just works (no Rust toolchain needed)
- Blazing Fast - Rust-powered validation that scales with your traffic
- Battle-Tested - Built on the proven
jsonschemaRust crate - Great Errors - Clear, actionable validation error messages
- Spec Compliant - Supports JSON Schema draft-07, 2019-09, and 2020-12
Installation
def deps do
[{:ex_jsonschema, "~> 0.1.1"}]
endThat's it! No Rust toolchain needed.
Quick Start
# Define your schema
schema = ~s({
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "number", "minimum": 0}
},
"required": ["name"]
})
# Compile once, validate many times
{:ok, validator} = ExJsonschema.compile(schema)
# Validate your data
:ok = ExJsonschema.validate(validator, ~s({"name": "Alice", "age": 30}))
# Get helpful errors
{:error, errors} = ExJsonschema.validate(validator, ~s({"age": -5}))
# => [%{message: "\"name\" is a required property", instance_path: ""}]That's it! Compile your schema once, then validate as much data as you need.
External Schema Resolution
Schemas that use $ref to reference external URLs are fully supported. By default, external refs are silently ignored (no network calls from inside the NIF). You control resolution in Elixir:
# Default: ignore unknown $refs (permissive, no network I/O)
{:ok, compiled} = ExJsonschema.compile(schema)
# Pre-resolved map: you fetch the schemas however you want
{:ok, compiled} = ExJsonschema.compile(schema,
external_schemas: %{
"https://example.com/address.json" => ~s({"type": "object", ...})
}
)
# Behaviour-based resolver: handles transitive refs automatically
{:ok, compiled} = ExJsonschema.compile(schema, ref_resolver: MyApp.SchemaResolver)
# Inspect what refs a schema needs
{:ok, refs} = ExJsonschema.extract_refs(schema)
#=> ["https://example.com/address.json", "https://example.com/person.json"]
Implement the ExJsonschema.RefResolver behaviour to resolve refs from HTTP, a database, the filesystem, or anything else:
defmodule MyApp.SchemaResolver do
@behaviour ExJsonschema.RefResolver
@impl true
def resolve(uris) do
resolved = Map.new(uris, fn uri ->
{:ok, %{body: body}} = Req.get(uri)
{uri, body}
end)
{:ok, resolved}
end
endMore Features
ExJsonschema includes everything you need for production use:
- External Ref Resolution - Behaviour-based resolver, pre-resolved maps, or ignore mode
- Performance Profiles -
:strict,:lenient, and:performancepresets - Flexible Output - Choose between
:basic,:detailed, and:verboseerror formats - Schema Caching - Automatic caching for schemas with
$idfields - Stream Processing - Works great with Elixir's
Streammodule - Format Validation - Email, URI, date-time, and more built-in formats
# Performance tuned for your use case
opts = ExJsonschema.Options.new(:performance)
ExJsonschema.validate(validator, data, opts)
# Just need a boolean?
ExJsonschema.valid?(validator, data)Documentation
For detailed usage, check out the guides:
- Getting Started - Learn the basics with practical examples
- Advanced Features - Profiles, caching, and integration patterns
- Streaming Validation - Process large datasets efficiently
- Performance & Production - Optimization and deployment
Benchmarking
Test performance on your system:
mix benchmarkLicense
MIT - see LICENSE file for details.