View Source Peri (peri v0.2.1)

Peri is a schema validation library for Elixir, inspired by Clojure's Plumatic Schema. It focuses on validating raw maps and supports nested schemas and optional fields.

Usage

To define a schema, use the defschema macro. By default, all fields in the schema are optional unless specified as {:required, type}.

defmodule MySchemas do
  import Peri

  defschema :user, %{
    name: :string,
    age: :integer,
    email: {:required, :string},
    address: %{
      street: :string,
      city: :string
    },
    tags: {:list, :string},
    role: {:enum, [:admin, :user, :guest]},
    geolocation: {:tuple, [:float, :float]},
    rating: {:custom, &validate_rating/1}
  }

  defp validate_rating(n) when n < 10, do: :ok
  defp validate_rating(_), do: {:error, "invalid rating", []}
end

You can then use the schema to validate data:

user_data = %{name: "John", age: 30, email: "john@example.com", address: %{street: "123 Main St", city: "Somewhere"}, tags: ["science", "funky"], role: :admin, geolocation: {12.2, 34.2}, rating: 9}
case MySchemas.user(user_data) do
  {:ok, valid_data} -> IO.puts("Data is valid!")
  {:error, errors} -> IO.inspect(errors, label: "Validation errors")
end

Available Types

  • :string - Validates that the field is a binary (string).
  • :integer - Validates that the field is an integer.
  • :float - Validates that the field is a float.
  • :boolean - Validates that the field is a boolean.
  • :atom - Validates that the field is an atom.
  • :any - Allow any datatype.
  • {:required, type} - Marks the field as required and validates it according to the specified type.
  • :map - Validates that the field is a map without checking nested schema.
  • {:either, {type_1, type_2}} - Validates that the field is either of type_1 or type_2.
  • {:oneof, types} - Validates that the field is at least one of the provided types.
  • {:list, type} - Validates that the field is a list where elements belongs to a determined type.
  • {:tuple, types} - Validates that the field is a tuple with determined size and each element have your own type validation (sequential).
  • {custom, anonymous_fun_arity_1} - Validates that the field passes on the callback, the function needs to return either :ok or {:error, reason} where reason should be a string.
  • {:custom, {MyModule, :my_validation}} - Same as {custom, anonymous_fun_arity_1} but you pass a remote module and a function name as atom.
  • {:custom, {MyModule, :my_validation, [arg1, arg2]}} - Same as {:custom, {MyModule, :my_validation}} but you can pass extra arguments to your validation function. Note that the value of the field is always the first argument.

Summary

Functions

Defines a schema with a given name and schema definition.

Validates a given data map against a schema.

Functions

Link to this macro

defschema(name, schema)

View Source (macro)

Defines a schema with a given name and schema definition.

Examples

defmodule MySchemas do
  import Peri

  defschema :user, %{
    name: :string,
    age: :integer,
    email: {:required, :string}
  }
end

user_data = %{name: "John", age: 30, email: "john@example.com"}
MySchemas.user(user_data)
# => {:ok, %{name: "John", age: 30, email: "john@example.com"}}

invalid_data = %{name: "John", age: 30}
MySchemas.user(invalid_data)
# => {:error, [email: "is required"]}

Validates a given data map against a schema.

Returns {:ok, data} if the data is valid according to the schema, or {:error, errors} if there are validation errors.

Parameters

  • schema: The schema definition map.
  • data: The data map to be validated.

Examples

schema = %{
  name: :string,
  age: :integer,
  email: {:required, :string}
}

data = %{name: "John", age: 30, email: "john@example.com"}
Peri.validate(schema, data)
# => {:ok, %{name: "John", age: 30, email: "john@example.com"}}

invalid_data = %{name: "John", age: 30}
Peri.validate(schema, invalid_data)
# => {:error, [email: "is required"]}