Easy data validation with with Valdi in Elixir

Image not Found

Credit: this icon is from flaticon.com

In previous article, I shown you how to implement you own validation module. I you haven’t read it, you can find it here How to build an Elixir validator from scratch

And I think some of you may want a ready to use library so I wrapped it up, added some useful api and published on hex.pm and github repo here.

This post is just showcases of what it can do. (not too much fancy) First, add dependencies to your mix.exs and you are ready to go.

1{:valdi, "~> 0.2.0"}

And this is how it works.

Validate using a specific validation function

1iex(1)> age = 20
220
3iex(2)> Valdi.validate_number(age, min: 18, max: 60)
4:ok

But most of the time you don’t do this, you will want to combine multiple validations at a time.

1iex(4)> Valdi.validate("20", type: :integer,  number: [min: 18, max: 60])
2{:error, "is not a integer"}

And you may want to validate a list of value too:

1iex(1)> Valdi.validate_list(["hi", "how", "are", "you", 100], type: :string,  length: [min: 3])
2{:error,
3 [[0, "length must be greater than or equal to 3"], [4, "is not a string"]]}

If validation failed, you got a list of error and index of error item.

Valdi supports you to validate a simple map with given specification:

 1product_spec = %{
 2    name: [type: :string, required: true],
 3    sku: [type: :string, required: true],
 4    price: [type: :integer, number: [min: 0]]
 5}
 6Valdi.validate_map(%{
 7    name: "A magic pen",
 8    sku: nil,
 9    price: -1
10}, product_spec)
11
12# {:error, %{price: "must be greater than or equal to 0", sku: "is required"}}

Valdi does not support nested map validation.

You might want to take a look at Contrak, it extended Valdi by providing a simple way to define and validate nested schema.

Why I didn’t put those in just one library? I think data validation and schema validation are quite different, so I want to keep libraries simple and do its best thing.

Here you can define your own validation

1Valdi.validate("as008x8234", type: :string, func: fn value ->
2   if String.match?(value, ~r/^\d{4}$/), do: :ok, else: {:error, "not a year string"}
3end)
4
5# {:error, "not a year string"}

Hope this small library can help. If you have any suggestion please comment. Thank you.