Peri is a schema validation library for Elixir, inspired by Clojure's Plumatic Schema. It provides a powerful and flexible way to define and validate schemas for your data, ensuring data integrity and consistency throughout your application.

Features

  • Schema Definition: Define schemas using a concise and expressive DSL
  • Nested Validation: Support for deeply nested and complex schemas
  • Custom Validation: Implement custom validation functions for specific requirements
  • Data Generation: Generate sample data based on your schemas using StreamData
  • Ecto Integration: Convert Peri schemas to Ecto changesets for seamless database integration
  • Phoenix Integration: Build Phoenix.HTML.Form structs from schemas with Peri.Phoenix.to_form/3, no Ecto required
  • Validation Modes: Choose between strict (default) and permissive validation modes
  • Schema Metadata: Attach docs, examples, and tooling hints via {:meta, type, opts} and schema-level meta opts
  • JSON Schema: Bidirectional conversion (Draft 7) via Peri.to_json_schema/2 and Peri.from_json_schema/1
  • Refs: Recursive and cross-module schemas via {:ref, atom} and {:ref, {Mod, atom}}
  • Custom Errors / i18n: Per-field error: overrides (static or MFA) and Peri.Error.traverse_errors/2 for Gettext-style translation
  • Error Rendering: Peri.Error.humanize/1 produces Ecto-style data-shaped error maps; missing required keys get "did you mean" suggestions
  • Schema Transformation: Depth-first rewrite via Peri.walk/2 — make-all-optional, strip-fields, rename, etc.
  • Schema Composition: Build schemas from schemas with Peri.merge/2, Peri.select/2, and Peri.except/2
  • Custom Generators: Per-field gen: opt to override StreamData generation on tight constraint domains
  • Coercion / Codecs: {:coerce, source, target} turns string params into typed data, with Peri.encode/3 for the reverse direction

Installation

Add this line to your mix.exs:

defp deps do
  [
    {:peri, "~> 0.10.0"} # x-release-please-version
  ]
end

Quick Start

defmodule MyApp.Schemas do
  import Peri

  defschema :user, %{
    name: {:required, :string},
    age: {:integer, {:gte, 18}},
    email: {:required, :string},
    role: {:enum, [:admin, :user, :guest]}
  }
end

# Validate data
data = %{name: "John", age: 25, email: "john@example.com", role: :user}
MyApp.Schemas.user(data)
# => {:ok, validated_data}

# Validate with permissive mode (preserves extra fields)
data_with_extra = %{name: "John", age: 25, email: "john@example.com", role: :user, extra: "field"}
Peri.validate(MyApp.Schemas.get_schema(:user), data_with_extra, mode: :permissive)
# => {:ok, %{name: "John", age: 25, email: "john@example.com", role: :user, extra: "field"}}

Documentation

For detailed documentation on types, validation patterns, and integrations, see:

Why the Name "Peri"?

The name "Peri" is derived from the Greek word "περί" (pronounced "peri"), which means "around" or "about." This name was chosen to reflect the library's primary purpose: to provide comprehensive and flexible schema validation for data structures in Elixir. Just as "peri" suggests encompassing or surrounding something, Peri aims to cover all aspects of data validation, ensuring that data conforms to specified rules and constraints.

The choice of the name "Peri" also hints at the library's ability to handle a wide variety of data types and structures, much like how the term "around" can denote versatility and inclusiveness. Whether it's validating nested maps, complex tuples, or strings with specific patterns, Peri is designed to be a robust tool that can adapt to various validation needs in Elixir programming.