JSV

hex.pm VersionBuild StatusLicense

JSV is a JSON Schema validator for Elixir, designed for modern applications. It provides full compliance with the latest JSON Schema specifications while offering a seamless, Elixir-native developer experience.

Key Features

Documentation

Comprehensive guides and API documentation are available on hexdocs.pm.

Supported Dialects

JSV supports 100% of features from Draft 2020-12 and Draft 7 as verified by the JSON Schema Compliance Test Suite.

Installation

Add jsv to your mix.exs:

def deps do
[
{:jsv, "~> 0.19"},
]
end

Optional Dependencies

JSV integrates with popular Elixir libraries to provide enhanced functionality:

def deps do
[
# JSV Supports Decimal and will validate Decimal structs as numbers.
{:decimal, "~> 2.0"},
# Required for resolving schemas via HTTP on Elixir < 1.18.
{:jason, "~> 1.0"}
]
end

Usage

Simple Validation

schema = %{
type: :object,
properties: %{
name: %{type: :string}
},
required: [:name]
}
root = JSV.build!(schema)
case JSV.validate(%{"name" => "Alice"}, root) do
# %{"name" => "Alice"}
{:ok, data} -> IO.inspect(data)
{:error, err} -> IO.inspect(JSV.normalize_error(err))
end

Module-Based Schemas

Define your business objects and validation logic in one place:

defmodule MyApp.User do
use JSV.Schema
defschema %{
type: :object,
properties: %{
name: string(minLength: 1),
age: integer(minimum: 0, default: 18)
},
required: [:name]
}
end
# Build at compile-time for maximum performance
root = JSV.build!(MyApp.User)
# Casting to structs is enabled by default
%MyApp.User{name: "Alice", age: 18} = JSV.validate!(%{"name" => "Alice"}, root)

Pydantic style modules

use JSV.Schema
defschema MyApp.Data.Food,
~SD"""
A Tasty dish, hopefully
""",
name: string(),
origin: string()
defschema MyApp.Data.Profile,
~SD"""
Information about a user profile
""",
name: string(),
birthdate: optional(date()),
favorite_food: MyApp.Data.Food
defschema MyApp.Data.User,
~SD"""
System user information
""",
profile: MyApp.Data.Profile,
role: string_enum_to_atom([:admin, :writer, :reader])
data = %{
"profile" => %{
"name" => "Alice",
"birthdate" => "1994-01-08",
"favorite_food" => %{
"name" => "Pad Thai",
"origin" => "Thailand"
}
},
"role" => "admin"
}
root = JSV.build!(MyApp.Data.User, formats: true, atoms: true)
JSV.validate!(data, root, cast_formats: true)

With this simple module form you can define many struct schemas in a compact way. The code above will cast the data (and the birthdate as well):

%MyApp.Data.User{
profile: %MyApp.Data.Profile{
birthdate: ~D[1994-01-08],
favorite_food: %MyApp.Data.Food{name: "Pad Thai", origin: "Thailand"},
name: "Alice"
},
role: :admin
}

Roadmap

Features and changes for v1.0.0 release:

Future changes:

Contributing

Please ensure your changes include thorough tests and follow the existing documentation style.

License

JSV is released under the Apache License Version 2.0.