π•°π–π–›π–†π–‘π–Žπ–‡π–šπ–— (Exvalibur) β†’ Smart Validation In Elixir

validation
exvalibur
#1

Exvalibur is the generator for blazingly fast validators of maps based on sets of predefined rules.

Under the hood, it generates a module with many different clauses of the same valid?/1 function with explicitly hardcoded pattern matches and guards on the input.

Here is the blog post shedding a light on what goodness it provides and h)ow is it implemented β†’ https://dev.to/mudasobwa/--smart-validation-in-elixir-4bcm

16 Likes

#2

As I continue working on Exvalibur, I have implemented custom guards and pattern matching of values.

I just blogged about how I used custom sigils to allow quoted expressions in the rules.

4 Likes

#3

Heh, interesting idea there!

0 Likes

#4

Where exactly? Do you mean a validator module generation? If yes, I can assure you it is worth it: we use it in production for several months and it shows itself :+1:

Depending on input, it runs 10–1000 times faster than standard validations.

1 Like

#5

Starting with v0.8.0 Exvalibur accepts module-based validatiors:

defmodule Validator do
  use Exvalibur, rules: [
    %{
      matches: %{currency_pair: <<"EUR", _ :: binary>>},
      conditions: %{foo: %{min: 0, max: 100}},
      guards: %{num: num > 0 and num < 100}}]
end

Validator.valid?(%{currency_pair: "EURUSD", foo: 50, num: 50})
#β‡’ {:ok, %{currency_pair: "EURUSD", foo: 50, num: 50}}
Validator.valid?(%{currency_pair: "USDEUR", foo: 50, num: 50})
#β‡’ :error
3 Likes

#6

I tend to think that there is a convention that functions with ? should return boolean type

2 Likes

#7

True that, but I struggled to find a better name to be short and self-explanatory. OTOH, I do not want to miss the opportunity to return what was indeed validated on success.

Maybe I should go with validate/1 to return what valid?/1 currently returns and valid?/1 to return boolean.

5 Likes

#8

For what it’s worth, here’s the convention about trailing question marks and boolean return values: https://hexdocs.pm/elixir/master/naming-conventions.html#trailing-question-mark-foo

4 Likes

#9

This is of course subjective, but personally I think that proposal is indeed more self-evident. :slight_smile:

1 Like

#10

It surely is. The only thing that prevents me of doing it straight away is it’s breaking change. I probably will go with deprecation warnings and validate/1 doing exactly what valid?/1 does now and change the behaviour of valid?/1 to return boolean as of v1.0.0.

2 Likes

#11
    @deprecated "Use #{__MODULE__}.validate/1 instead"
    def valid?(any), do: validate(any)

β†’ v0.9.0.

2 Likes

#12

Custom validations in the modules using Exvalibur. @behaviour Exvalibur.Validatable.

defmodule CustomValidator do
  use Exvalibur, rules: [
    %{conditions: %{foo: %{min: 0, max: 10}}}]

  @impl Exvalibur.Validatable
  def custom_validate(%{foo: foo}),
    do: if foo == 42, do: {:ok, %{foo: 42}}, else: :error
end

And then:

CustomValidator.validate(%{foo: 5})
{:ok, %{foo: 5}}
CustomValidator.validate(%{foo: 50})
:error
CustomValidator.validate(%{foo: 42})
{:ok, %{foo: 42}}

β†’ v0.10.0.

1 Like