View Source Dsv (Dsv v0.2.1)

The Dsv module provides a set of functions for validating user data of various types. In addition to simple data types such as strings, numbers, and dates, this module offers functionality for validating complex data structures like maps, lists, and structs.

Getting Started

The simplest way to utilize this library is by using the Dsv.validate/2 function with specified validation options. This function supports various validators, which you can explore in the "Basic Validators" section of the documentation. These validators include :length, :number, :format, and more.

Example - validate a simple value with multiple validators.

"This is an example of validating a simple string value"
|> Dsv.validate(length: [min: 10, max: 100], format: ~r/[A-Z][a-z]+/)

In this example, the string value is checked against several constraints: its length must be at least 10 and at most 100 graphemes, and it must start with an uppercase letter followed by at least one lowercase letter.

Basic validators

Here is a list of basic validators and their corresponding modules (the name on the left is also a name that need to be used in the Dsv.validate/2 and Dsv.valid?/2 functions):

For detailed descriptions of each validator and their available options, refer to the respective validator's documentation.

Validating complex data structures

The preferred way to validate complex data structures is by following these steps:

  1. Call Dsv.validation/1 with the data to validate as the first argument.
  2. Add validators for each field by specifying the path in the second argument of Dsv.add_validator/3 function and validators options in the third argument.
  3. Finally, run the validation by calling Dsv.validate/1

Example - validate nested maps with multiple validators.

%{a: "First value", b: %{c: "This is a nested map", d: 10, e: [1, 2, 3]}}
|> Dsv.validation
|> Dsv.add_validator([:a], length: [min: 1, max: 20], format: ~r/.*e/)
|> Dsv.add_validator([:b, :d], number: [gt: 4])
|> Dsv.add_validator([:b, :e], position: ["2": [equal: 2]])
|> Dsv.validate

You can also validate the same data by specifying map with validators that reflects the structure of the validated data.

Example - validate nested maps with multiple validators with validators as a map.

Same validator as in the above example can be written in the form of a map that reflects the validated data structure.

%{a: "First value", b: %{c: "This is a nested map", d: 10, e: [1, 2, 3]}}
|> Dsv.validate(%{
  :a => [length: [min: 1, max: 20], format: ~r/.*e/],
  :b => %{
    :d => [number: [gt: 4]],
    :e => [position: ["2": [equal: 2]]]
  }
})

Interchangeable approaches

The two approaches mentioned above are interchangeable, and it's up to the user to choose which one to use.

For more ways of writing validators look at: How to validate

Summary

Types

Data to validate of any type.

A map of validation errors.

A keyword list or map representing validation options.

A non-empty list containing elements of the path for the field in the data to validate.

A result of the validation, which can be :ok for success or {:error, errors} for failure.

A structure containing data for validation alongside the related validators.

Functions

Add a validator definition for the input data.

Add a validator definition for the input data, with a second path for value that will be used as an argument in the validator option.

Add binded value to the map of binded values. Those values can be used during the validation by calling Dsv.binded/1 with the name provided in this function.

Use binded value in the validator option.

Transform a list of paths and validator descriptions into a map of validators.

Set a custom message for the validation.

Run all validators defined in the second argument agains data provided as the first argument.

Same as Dsv.valid?/2 but with additional argument containing binded values.

Run validation based on the data in the validators() struct.

Validate input data according to the provided validation options.

This function works like validate/2 with an additional list of comparators that define validators using values from other input fields as their option values.

Validate input data according to the provided validation options and return a custom message in case of failure.

Run validation for %Validators{}

Types

@type data() :: any()

Data to validate of any type.

@type errors() :: map()

A map of validation errors.

@type options() :: keyword() | map()

A keyword list or map representing validation options.

Options can be provided in one of the two forms:

  • map() - this form is intended for input data where input data is treated as multiple fields to validate.
  • keyword() - this for is intended for input data where input data is treated as one whole value to validate
@type path() :: [String.t() | atom() | list(), ...]

A non-empty list containing elements of the path for the field in the data to validate.

Example

%{"user" => %{
    "name" => "User name", "last_name" => "User last name", "age" => 30, "address" => %{
      "street" => "Street", "postal_code" => "00900"
    }
  }
}

Path to the postal code field is the list of all keys in the map that carry on to the posta_code field. In this case the path will look like this:

["user", "address", "postal_code"]
@type validation_result() :: :ok | {:error, errors()}

A result of the validation, which can be :ok for success or {:error, errors} for failure.

@type validators() :: %Dsv.Validators{
  binded_values: map() | none(),
  comparators: [list()] | none(),
  data: map() | none(),
  message: String.t() | none(),
  validators: [...]
}

A structure containing data for validation alongside the related validators.

Fields

  • data - input data to validate
  • validators - map containing paths to data in data field with related validators
  • comparators - list with comparators definitions
  • message - custom messaege returned in case of validation failure
  • binded_values - names of the binded values with path to those values

Functions

Link to this function

add_validator(validators, path, new_validators)

View Source
@spec add_validator(any(), path(), options()) :: validators()

Add a validator definition for the input data.

Example

validators = %Validators{}
add_validator(validators, [:path, :to, :the, :validated, :field], length: [min: 1, max: 10], not_empty: :true)
Link to this function

add_validator(validators, path, path_to_compare, new_validators)

View Source
@spec add_validator(validators(), path(), path(), options()) :: validators()

Add a validator definition for the input data, with a second path for value that will be used as an argument in the validator option.

Example

validators = %Validators{}
add_validator(validators, [:path, :to, :the, :validated, :field], [:path, :to, :expected, :length], length: [min: 1, max: 10], not_empty: :true)
Link to this function

bind(validators, path, name)

View Source

Add binded value to the map of binded values. Those values can be used during the validation by calling Dsv.binded/1 with the name provided in this function.

Use binded value in the validator option.

Transform a list of paths and validator descriptions into a map of validators.

Example

iex> Dsv.paths([
  ["name", length: [min: 1, max: 3], format: ~r/(B|b)r[a-z]{3,5}k/],
  ["age", not_empty: true, number: [gt: 10, lt: 30]]
])
%{
  name: [length: [min: 1, max:3], format: ~r/(B|b)r[a-z]{3,5}k/],
  age: [not_empty: true, number: [gt: 10, lt: 30]]
}
Link to this function

set_custom_message(validators, message)

View Source
@spec set_custom_message(
  %Dsv.Validators{
    binded_values: term(),
    comparators: term(),
    data: term(),
    message: term(),
    validators: term()
  },
  String.t()
) :: %Dsv.Validators{
  binded_values: term(),
  comparators: term(),
  data: term(),
  message: term(),
  validators: term()
}

Set a custom message for the validation.

Link to this function

valid?(validators, data)

View Source
@spec valid?(data(), options()) :: boolean()

Run all validators defined in the second argument agains data provided as the first argument.

Parameters

  • data (data()) - data provided by the user
  • options (keyword()) - validation options, describe the rules that will be checked against input data

Returns

  • :true Represents successful validation, where all validation rules are met by the validated data.
  • :false is returned when any of the validation criteria are not met by the validated data.

Example

Dsv.valid?("Simple string", length: [min: 2, max: 20])
:true

Dsv.valid?("Simple string", length: [min: 2, max: 10])
:false
Link to this function

valid?(data, options, binded_values)

View Source

Same as Dsv.valid?/2 but with additional argument containing binded values.

Parameters

  • data (data()) - data provided by the user
  • options (keyword()) - validation options, describe the rules that will be checked against input data
  • binded_values (map()) - map containing names that can be used in validation options and paths from where value should be taken.

Returns

  • :true Represents successful validation, where all validation rules are met by the validated data.
  • :false is returned when any of the validation criteria are not met by the validated data.
@spec validate(%Dsv.Validators{
  binded_values: term(),
  comparators: term(),
  data: term(),
  message: term(),
  validators: term()
}) :: validation_result()
@spec validate(%Dsv.Validators{
  binded_values: term(),
  comparators: term(),
  data: term(),
  message: term(),
  validators: term()
}) :: validation_result()

Run validation based on the data in the validators() struct.

Parameters

  • validators() - %Validators{} struct containing all the information needed to run validation.

Return validation_result()

  • :ok - on successful validation, where all validation rules are met by the validated data.
  • {:error, errrors()} - on failure, when any fo the validation ciriteria are not met by the validated data.

Example

%Validators{data: %{"user" => %{"name" => "User name"}}, validators: %{"user" => "name" => [length: [min: 2]]}} |> Dsv.validate()
:ok
@spec validate(data(), options()) :: validation_result()

Validate input data according to the provided validation options.

Parameters

  • data() - data to validate
  • options() - validation options

Returns validation_result()

  • :ok - on successful validation, where all validation rules are met by the validated data.
  • {:error, errrors()} - on failure, when any fo the validation ciriteria are not met by the validated data.

Example

defmodule Person do
  defstruct [:name, :age, :eyes]
end

person = %Person{
  name: "Martin",
  age: 30,
  eyes: :blue
}

iex> Dsv.validate(person , %{name: [length: [min: 2, max: 20], format: ~r/[A-Z][0-9]+/]})
[
  errors: %{
    name: [error: "Value Martin does not match pattern [A-Z][0-9]+"]
  }
]

As in the example, validators can be joined to create a more complex check (in this case length and format). Dsv.validate/2 allow to validate any kind of data from numbers and strings to lists, maps and structs.

For more information how to use Dsv.validate/2 function go to How to validate

Link to this function

validate(data, options, comparators)

View Source

This function works like validate/2 with an additional list of comparators that define validators using values from other input fields as their option values.

Link to this function

validate(data, options, comparators, list)

View Source

Validate input data according to the provided validation options and return a custom message in case of failure.

Parameters

  • data - data to validate
  • options - validation options
  • comparators - list of comparators to use in validators
  • message - custom message that will be return in case of failure

Returns validation_result()

  • :ok - on successful validation, where all validation rules are met by the validated data.
  • {:error, message} - on failure, when any fo the validation ciriteria are not met by the validated data.

Example

defmodule Person do
  defstruct [:name, :age, :eyes]
end

person = %Person{
  name: "Martin",
  age: 30,
  eyes: :blue
}

iex> Dsv.validate(person , %{name: [length: [min: 2, max: 20], format: ~r/[A-Z][0-9]+/]}, [[:name], [:eyes], [:equal]], message: "Something goes wrong! Fix your data and try again.")
{:error, "Something goes wrong! Fix your data and try again."}

As in the example, validators can be joined to create a more complex check (in this case length and format). Dsv.validate/2 allow to validate any kind of data from numbers and strings to lists, maps and structs.

For more information how to use Dsv.validate/2 function go to How to validate

Run validation for %Validators{}