Elixact is a powerful schema definition and validation library for Elixir, inspired by Python's Pydantic. It provides a rich DSL for defining schemas with strong type validation, automatic JSON Schema generation, and excellent developer experience.
- 🎯 Rich Schema DSL - Intuitive and expressive schema definitions
- 🔍 Strong Type Validation - Comprehensive validation for basic and complex types
- 📊 JSON Schema Support - Automatic generation of JSON Schema from your Elixir schemas
- 🧩 Custom Types - Easily define reusable custom types
- 🎄 Nested Schemas - Support for deeply nested data structures
- ⛓️ Field Constraints - Rich set of built-in constraints
- 🚨 Structured Errors - Clear and actionable error messages
Add elixact
to your list of dependencies in mix.exs
:
def deps do
[
{:elixact, "~> 0.1.0"}
]
end
defmodule UserSchema do
use Elixact
schema "User account information" do
field :name, :string do
description "User's full name"
min_length 2
max_length 50
end
field :age, :integer do
description "User's age"
gt 0
lt 150
optional true
end
field :email, :string do
format ~r/^[^\s]+@[^\s]+$/
end
field :tags, {:array, :string} do
description "User tags"
min_items 0
max_items 5
default []
end
config do
title "User Schema"
strict true
end
end
end
# Validate data
case UserSchema.validate(%{
name: "John Doe",
email: "john@example.com",
age: 30,
tags: ["admin"]
}) do
{:ok, validated_data} ->
# Use validated data
IO.inspect(validated_data)
{:error, errors} ->
# Handle validation errors
Enum.each(errors, &IO.puts(Elixact.Error.format(&1)))
end
# Or use bang version which raises on error
validated = UserSchema.validate!(data)
defmodule ComplexSchema do
use Elixact
schema do
# Array of maps
field :metadata, {:array, {:map, {:string, :any}}} do
min_items 1
description "Metadata entries"
end
# Union type
field :id, {:union, [:string, :integer]} do
description "User ID (string or integer)"
end
# Nested schema
field :address, AddressSchema do
optional true
end
# Map with specific key/value types
field :settings, {:map, {:string, {:union, [:string, :boolean, :integer]}}} do
description "User settings"
default %{}
end
end
end
defmodule Types.Email do
use Elixact.Type
def type_definition do
Elixact.Types.string()
|> Elixact.Types.with_constraints([
format: ~r/^[^\s]+@[^\s]+$/
])
end
def json_schema do
%{
"type" => "string",
"format" => "email",
"pattern" => "^[^\\s]+@[^\\s]+$"
}
end
end
# Generate JSON Schema
json_schema = Elixact.JsonSchema.from_schema(UserSchema)
# The schema can be used with any JSON Schema validator
json = Jason.encode!(json_schema)
- Basic Types:
:string
,:integer
,:float
,:boolean
,:any
- Complex Types:
- Arrays:
{:array, type}
- Maps:
{:map, {key_type, value_type}}
- Unions:
{:union, [type1, type2, ...]}
- Custom Types: Any module implementing
Elixact.Type
behaviour - Nested Schemas: References to other schema modules
- Arrays:
- Strings:
min_length
,max_length
,format
(regex) - Numbers:
gt
,lt
,gteq
,lteq
- Arrays:
min_items
,max_items
- General:
required
,optional
,default
,choices
Elixact provides structured error messages with path information:
{:error, [
%Elixact.Error{
path: [:email],
code: :format,
message: "invalid email format"
}
]}
- Fork it
- Create your feature branch (
git checkout -b feature/my-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin feature/my-feature
) - Create a new Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.