There is no solution which covers all use cases, but a pure Elixir validation is pretty simple to write, for example with code below:
defmodule Example do
@required_keys ~w[sample]a
@enforce_keys @required_keys
defstruct [:sample]
def sample(data) when is_list(data) do
@required_keys
|> Enum.reject(&Keyword.has_key?(data, &1))
|> sample(data)
end
defp sample([], data) do
case validate(data) do
{:error, reason} -> {:error, reason}
data -> struct(__MODULE__, data)
end
end
defp sample(missing_fields, _data) do
{:error, "missing fields: " <> Enum.join(missing_fields, ", ")}
end
def sample!(data) when is_list(data) do
case validate(data) do
{:error, reason} -> raise reason
data -> struct!(__MODULE__, data)
end
end
defp validate(data) do
Enum.reduce_while(data, %{}, fn {key, value}, acc ->
case validate(key, value) do
# when value is validated put it using key
{:ok, value} -> {:cont, Map.put(acc, key, value)}
# otherwise when validation fails return error
{:error, reason} -> {:halt, {:error, reason}}
end
end)
end
defp validate(:sample, value) when is_integer(value), do: {:ok, value}
defp validate(:sample, _value), do: {:error, "sample is not an integer"}
defp validate(_key, value), do: {:ok, value}
end
the struct would not be validated (except @enforce_keys when using it “by hand” like %Example{}. Officially there is no support for preventing others to use write struct by hand.






















