Fild (fild v0.1.1)
Utilities for extracting and validating typed fields from maps or keyword lists.
This module provides functions to fetch required (get_mandatory/3) and optional
(get_optional/3) fields from a map or keyword list, validating their presence and type.
Examples
Fild.get_mandatory(%{age: 20}, :age, :integer)
#=> {:ok, 20}
Fild.get_mandatory(%{}, :age, :integer)
#=> {:error, "expected :age to be given"}
Fild.get_mandatory(%{age: "20"}, :age, :integer)
#=> {:error, "expected :age to be integer, got: \"20\""}
Fild.get_optional(%{}, :mode, :atom, :default)
#=> {:ok, :default}Bang Variants
All functions also have a ! variant (e.g. get_mandatory!/3) that raises
an error on validation failure instead of returning an {:error, reason} tuple.
Summary
Functions
Fetches a mandatory key from the given args, validates its type, and returns
{:ok, value} on success, or {:error, reason} if the key is missing or invalid.
Fetches a mandatory key from the given args, validates its type against the provided type specification,
and returns the value directly.
Fetches an optional key from args, validates its type if present,
and returns {:ok, value} or {:ok, default} if the key is missing.
Fetches an optional key from args, validates its type if present,
and returns the value or the provided default.
Validates the given value against the specified type.
Types
@type field_type() :: simple_type() | {:one_of, [term()]} | {:list_of, simple_type()} | {:struct, module()}
@type simple_type() ::
:boolean
| :integer
| :float
| :number
| :binary
| :map
| :list
| :atom
| :non_empty_list
| :any
Functions
@spec get_mandatory(Access.t(), key :: term(), field_type()) :: {:ok, term()} | {:error, String.t()}
Fetches a mandatory key from the given args, validates its type, and returns
{:ok, value} on success, or {:error, reason} if the key is missing or invalid.
Examples
iex> Fild.get_mandatory(%{foo: 42}, :foo, :integer)
{:ok, 42}
iex> Fild.get_mandatory(%{}, :foo, :integer)
{:error, "expected :foo to be given"}
iex> Fild.get_mandatory(%{foo: "bar"}, :foo, :integer)
{:error, "expected :foo to be integer, got: "bar""}
@spec get_mandatory!(Access.t(), key :: term(), field_type()) :: term() | no_return()
Fetches a mandatory key from the given args, validates its type against the provided type specification,
and returns the value directly.
Raises a RuntimeError if the key is missing or if the value does not conform to the expected type.
Examples
iex> Fild.get_mandatory!(%{foo: 42}, :foo, :integer)
42
iex> Fild.get_mandatory!(%{}, :foo, :integer)
** (RuntimeError) expected :foo to be given
iex> Fild.get_mandatory!(%{foo: "bar"}, :foo, :integer)
** (RuntimeError) expected :foo to be integer, got: "bar"
@spec get_optional(Access.t(), key :: term(), field_type(), term()) :: {:ok, term()} | {:error, String.t()}
Fetches an optional key from args, validates its type if present,
and returns {:ok, value} or {:ok, default} if the key is missing.
Returns {:error, reason} if the key exists but the value is invalid.
Examples
iex> Fild.get_optional(%{foo: 42}, :foo, :integer, 0)
{:ok, 42}
iex> Fild.get_optional(%{}, :foo, :integer, 0)
{:ok, 0}
iex> Fild.get_optional(%{foo: "bar"}, :foo, :integer, 0)
{:error, "expected :foo to be integer, got: "bar""}
Fetches an optional key from args, validates its type if present,
and returns the value or the provided default.
Raises a RuntimeError if the key exists but the value is invalid.
Examples
iex> Fild.get_optional!(%{foo: 42}, :foo, :integer, 0)
42
iex> Fild.get_optional!(%{}, :foo, :integer, 0)
0
iex> Fild.get_optional!(%{foo: "bar"}, :foo, :integer, 0)
** (RuntimeError) expected :foo to be integer, got: "bar"
@spec validate_field(key :: atom(), value :: term(), field_type()) :: :ok | {:error, binary()}
Validates the given value against the specified type.
Returns :ok if the value matches the type, or {:error, reason} otherwise.
Examples
iex> Fild.validate_field(:foo, 42, :integer)
:ok
iex> Fild.validate_field(:foo, "bar", :integer)
{:error, "expected :foo to be integer, got: "bar""}
iex> Fild.validate_field(:foo, :a, {:one_of, [:a, :b]})
:ok
iex> Fild.validate_field(:foo, :c, {:one_of, [:a, :b]})
{:error, "expected :foo to be one of [:a, :b], got: :c"}
iex> Fild.validate_field(:foo, [1, 2], {:list_of, :integer})
:ok
iex> Fild.validate_field(:foo, [1, "no"], {:list_of, :integer})
{:error, "expected :foo to be a list of :integer, got: [1, "no"]"}
iex> Fild.validate_field(:foo, %URI{}, {:struct, URI})
:ok
iex> Fild.validate_field(:foo, %{}, {:struct, URI})
{:error, "expected :foo to be URI struct, got: %{}"}