Domo makes your structure types work for data conformance validation. And it enables automatic range checking for field types at run-time.
Domo adds a new/1
constructor function to the structure module that builds an instance only if all fields conform to the struct’s t()
type and all specified precondition functions for filed types return true.
That is useful for boundary data validation coming as decoded JSON from Jason
or from :erlang.binary_to_term/1
, and for validation when converting one core struct into another like in CQRS framework Commanded
.
Domo makes it possible to validate model types in microservice setups between depending applications by sharing common modules with type definitions among codebases.
See typical usage in Readme.md via:
Shortly it looks like:
defmodule Customer do
use Domo
defstruct title: :none, name: "", age: 0
@type title :: :mr | :ms | :dr | :none
@type name :: String.t()
@type age :: non_neg_integer()
precond age: &(&1 < 300)
@type t :: %__MODULE__{title: title(), name: name(), age: age()}
precond t: &(String.length(&1.name) < 10)
end
iex(1)> Customer.new(title: :dr, name: "John", age: 25)
{:ok, %Customer{age: 25, name: "John", title: :dr}}
iex(2)> Customer.new(title: :dr, name: nil, age: 25)
{:error, [name: "Invalid value nil for field :name of %Customer{}. Expected the value \
matching the <<_::_*8>> type."]}
iex(3)> Customer.new(title: :dr, name: "Johnny be good", age: 25)
{:error, [t: "Invalid value %Customer{age: 25, name: \"Johnny be good\", title: :dr}. \
Expected the value matching the Customer.t() type. And a true value from the precondition \
function \"&(String.length(&1.name) < 10)\" defined for Customer.t() type."]}
Example applications:
- Web-site with Ecto + Domo
- Integration with
TypedStruct
andTypedEctoSchema
libraries - JSON parsing and validation
- Commanded + Domo combo used in Event Sourcing and CQRS
Domo main features are:
- automatic generation of constructor and insurance functions validating struct’s fields conformance to
@type t()
, which are:new!/1
,new/1
,ensure_type!/1
, andensure_type/1
- validation of nested structs referenced in the type spec
- support for boolean precondition functions attached to the user-defined type or the whole struct’s
t()
type for values range check - validation of struct default values at compile-time
- recompilation of dependencies when type definition changes
More information here: