Packages
jsv
0.19.5
0.21.2
0.21.1
0.21.0
0.20.0
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.0
0.15.2
0.15.1
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.5
0.11.4
0.11.3
retired
0.11.2
0.11.1
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
A JSON Schema Validator with complete support for the latest specifications.
Current section
Files
Jump to
Current section
Files
README.md
# JSV
<!-- rdmx :badges
hexpm : "jsv?color=4e2a8e"
github_action : "lud/jsv/elixir.yaml?label=CI&branch=main"
license : jsv
-->
[](https://hex.pm/packages/jsv)
[](https://github.com/lud/jsv/actions/workflows/elixir.yaml?query=branch%3Amain)
[](https://hex.pm/packages/jsv)
<!-- rdmx /:badges -->
**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
- **Full Specification Compliance**: 100% support for **Draft 2020-12**
(including `$dynamicRef`, `$dynamicAnchor`, and all vocabularies) and **Draft
7**.
- **High Performance**: Schemas can be pre-compiled into an optimized internal
representation. Build your validation roots at compile-time for **near-zero
runtime overhead**.
- **Elixir-Native Schemas**: Use `defschema` to define schemas as Elixir
modules. Supports automatic casting to **Elixir structs** with default values.
- **Advanced Casting & Transformation**:
- Built-in support for casting to `Date`, `DateTime`, `Duration`, and
`Decimal`.
- Extensible casting system using the `x-jsv-cast` keyword and `defcast` macros.
- **Extensible Resolution**: Fetch remote schemas via HTTP or resolve them from
local files and directories using custom or built-in resolvers.
- **Flexible Workflows**: Supports schemas as atoms or binaries, from Elixir
code, JSON files, or the network. JSV supports many ways to work with schemas.
- **Extensible Vocabularies**: Thanks to features of Draft 2020-12, custom
meta-schemas with custom schema keywords are supported out of the box.
- **Functional Builder API**: Compose schemas dynamically using a functional
API.
- **Rich Error Handling**: Detailed validation errors that can be easily
normalized into JSON-compatible structures for API responses.
- **Complete support in [Oaskit](https://github.com/lud/oaskit)**: Oaskit is an
OpenAPI 3.1 validator for Phoenix and is entirely built on JSV.
## Documentation
[Comprehensive guides and API documentation are available on hexdocs.pm](https://hexdocs.pm/jsv/).
## Supported Dialects
JSV supports 100% of features from Draft 2020-12 and Draft 7 as verified by the
[JSON Schema Compliance Test Suite](https://bowtie.report/).
* [](https://bowtie.report/#/implementations/elixir-jsv)
* [](https://bowtie.report/#/implementations/elixir-jsv)
## Installation
Add `jsv` to your `mix.exs`:
<!-- rdmx :app_dep vsn:$app_vsn -->
```elixir
def deps do
[
{:jsv, "~> 0.19"},
]
end
```
<!-- rdmx /:app_dep -->
### Optional Dependencies
JSV integrates with popular Elixir libraries to provide enhanced functionality:
```elixir
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
<!-- rdmx :section format:true name:"simple-validation" -->
```elixir
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
```
<!-- rdmx /:section -->
### Module-Based Schemas
Define your business objects and validation logic in one place:
<!-- rdmx :section format:true name:"module-based" -->
```elixir
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)
```
<!-- rdmx /:section -->
### Pydantic style modules
<!-- rdmx :section format:true name:"pydantic" -->
```elixir
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)
```
<!-- rdmx /:section -->
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):
<!-- rdmx :eval section:pydantic -->
```elixir
%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
}
```
<!-- rdmx /:eval -->
## Roadmap
Features and changes for v1.0.0 release:
* [x] New cast system with caster arguments, migrate `jsv-cast` to `x-jsv-cast` keyword.
* [x] Struct-less atom-keyed maps cast.
Future changes:
* [ ] Custom vocabularies appendable to well-known metas like
`https://json-schema.org/draft/2020-12/schema`.
* [ ] Move `defschema` and `defcast` to `JSV.Schema`
* [ ] Remove support for legacy `jsv-cast` keyword.
## 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](LICENSE).