Gate

Hex.pmCircleCI

This is a simple API for validating data structures, mostly from user input like web forms or API requests.

Table of Contents

Installation

the package can be installed by adding gate to your list of dependencies in mix.exs and run mix deps.get:

def deps do
  [
    {:gate, "~> 0.1.3"}
  ]
end

Usage

Gate’s error message handling requires a JSON parser, a decoder must be set in config/config.exs

# config/config.exs

use Mix.Config
config :gate, decoder: Poison

Example:

  @schema %{
    "name" => :str
    "age" => :int,
    "gender" => {:include, ["male", "female"]},
    "pet_names" => {:each, :str},
    "more_info" => %{
      "telefone" => [:str, {:regex, ~r/custom_regex/}],
      "address" => [:optional, :str]
    },
    "relationships" => {:each,
      %{ "id" => :int, "type" => {:equal, "user" } }
    }
  }

  form_data = %{
    "name" => "Jon",
    "age" => 21,
    "gender" => "male",
    "pet_names" => ["jekyll", "hyde"],
    "exra_field" => "something", # It'll be ignored
    "more_info" => %{
      "telefone" => "custom_regex",
    },
    "relationships" => [
      %{ "id" => 1, "type" => "user" },
      %{ "id" => 2, "type" => "user" }
    ]
  }
  
  Gate.valid?(form_data, @schema)
  # { 
  #   :ok, 
  #   %{
  #     "name" => "Jon",
  #     "age" => 21,
  #     "gender" => "male",
  #     "pet_names" => ["jekyll", "hyde"],
  #     "more_info" => %{
  #       "telefone" => "custom_regex",
  #     },
  #    "relationships" => [
  #      %{ "id" => 1, "type" => "user" },
  #      %{ "id" => 2, "type" => "user" }
  #    ]
  #   } 
  # }

Rules

Type checks available:

You can make an attribute optional with :optional

More advanced rules are:

You can validate a field with multiple rules by using a list - [:str, {:equal, "spaghetti"}, {:custom, custom_rule()}]

If you wanna check the value of each element in a list you can use {:each, rule} for example:

Custom Rules

Example custom rule without the use of locales:

  def custom_rule do
    fn(value) ->
      if value == 1, do: true, else: "Value not equal to 1"
    end
  end
  
  Gate.valid?(1, {:custom, custom_rule()})
  # true
  Gate.valid?(2, {:custom, custom_rule()})
  # "Value not equal to 1"

If you want to make use of custom (Locales) you can do something like:

  def custom_rule do
    fn(value) ->
      if value == 1, do: true, else: { :locale, "custom_rule1" }
      # If you want to use the value in the locale 
      # you can pass it as a third argument like
      # if value == 1, do: true, else: { :locale, "custom_rule1", value }
    end
  end

Error messages

The default error messages are defined in here. They can be overridden by specifying your custom locale file in your config/config.exs

# config/config.exs

use Mix.Config
config :gate, locale_file: "assets/locale.json"

Example locale.json

{
  "int": "This will override the default int type check error",
  "custom_rule1": "Value does not match custom_rule1",
}

Example custom locale that changes the default :int rule and also expose the value:

{
  "int": "{} is not an integer"
}

{} will be replaced with the value that is being validated

  Gate.valid?("spaghetti", :int)
  # "spaghetti is not an integer"

License

MIT © gmartsenkov