Valdi (Valdi v0.6.0)
View SourceA comprehensive Elixir data validation library that provides flexible and composable validation functions.
Features
- Type validation - validate data types including numbers, strings, lists, maps, structs, and Decimal types
- Constraint validation - validate ranges, lengths, formats, and inclusion/exclusion
- Flattened validators - use convenient aliases like
min,max,min_lengthwithout nesting - Pattern matching - efficient validation dispatch using Elixir's pattern matching
- Composable - combine multiple validations in a single call
- Backward compatible - works with existing validation patterns
- Conditional type checking - skip type validation when not needed for better performance
Quick Examples
Basic validation
# Type validation
Valdi.validate("hello", type: :string)
#=> :ok
# Constraint validation without type checking
Valdi.validate("hello", min_length: 3, max_length: 10)
#=> :ok
# Combined validations
Valdi.validate(15, type: :integer, min: 10, max: 20, greater_than: 5)
#=> :okFlattened validators (new!)
# Instead of nested syntax
Valdi.validate("test", type: :string, length: [min: 3, max: 10])
# Use flattened syntax
Valdi.validate("test", type: :string, min_length: 3, max_length: 10)
# Mix both styles
Valdi.validate(15, min: 10, number: [max: 20])List and map validation
# Validate each item in a list
Valdi.validate_list([1, 2, 3], type: :integer, min: 0)
# Validate map with schema
schema = %{
name: [type: :string, required: true, min_length: 2],
age: [type: :integer, min: 0, max: 150],
email: [type: :string, format: ~r/.+@.+/]
}
Valdi.validate_map(%{name: "John", age: 30}, schema)Available Validators
Core validators
type- validate data typerequired- ensure value is not nilformat/pattern- regex pattern matchingin/enum- value inclusion validationnot_in- value exclusion validationfunc- custom validation function
Numeric validators
number- numeric constraints (nested)min- minimum value (≥)max- maximum value (≤)greater_than- strictly greater than (>)less_than- strictly less than (<)
Length validators
length- length constraints (nested)min_length- minimum lengthmax_length- maximum lengthmin_items- minimum array items (alias for min_length)max_items- maximum array items (alias for max_length)
Other validators
each- validate each item in arraysdecimal- decimal validation (deprecated, usenumberinstead)
Options
ignore_unknown: true- skip unknown validators instead of returning errors
Individual Validation Functions
Each validator can also be used independently:
Valdi.validate_type("hello", :string)
Valdi.validate_number(15, min: 10, max: 20)
Valdi.validate_length("hello", min: 3, max: 10)
Valdi.validate_inclusion("red", ["red", "green", "blue"])
Summary
Functions
Validate value against list of validations.
Validate decimal values.
Apply validation for each array item
Validate embed types
Check if value is not included in the given enumerable. Similar to validate_inclusion/2
Checks whether a string match the given regex pattern.
Check if value is included in the given enumerable.
Check if length of value match given conditions. Length condions are the same with validate_number/2
Validate list value aganst validator and return error if any item is not valid.
In case of error {:error, errors}, errors is list of error detail for all error item includes [index, message]
Validate map value with given map specification. Validation spec is a map
Validate number value
Validate value if value is not nil. This function can receive a function to dynamicall calculate required or not.
Validate data types.
Types
Functions
Validate value against list of validations.
iex> Valdi.validate("email@g.c", type: :string, format: ~r/.+@.+.[a-z]{2,10}/)
{:error, "does not match format"}All supported validations:
type: validate datatypeformat|pattern: check if binary value matched given regexnumber: validate number value (supports both regular numbers and Decimal types)length: validate length of supported types. Seevalidate_length/2for more details.in|enum: validate inclusionnot_in: validate exclusionmin: validate minimum value for numbersmax: validate maximum value for numbersgreater_than: validate value is greater than specified numberless_than: validate value is less than specified numbermin_length: validate minimum length for strings, lists, maps, tuplesmax_length: validate maximum length for strings, lists, maps, tuplesmin_items: validate minimum number of items in arrays (alias for min_length)max_items: validate maximum number of items in arrays (alias for max_length)func: custom validation function follows specfunc(any()):: :ok | {:error, message::String.t()}each: validate each item in list with given validator. Supports all above validatordecimal: validate decimal values (deprecated, usenumberinstead)
Options:
ignore_unknown: whentrue, unknown validators are ignored instead of returning an error (default:false)
iex> Valdi.validate("test", [type: :string, unknown_validator: :value], ignore_unknown: true)
:ok
iex> Valdi.validate("test", [type: :string, unknown_validator: :value], ignore_unknown: false)
{:error, "validate_unknown_validator is not supported"}
iex> Valdi.validate(15, type: :integer, min: 10, max: 20)
:ok
iex> Valdi.validate(15, type: :integer, greater_than: 10, less_than: 20)
:ok
iex> Valdi.validate("hello", type: :string, min_length: 3, max_length: 10)
:ok
iex> Valdi.validate([1, 2, 3], type: :list, min_items: 2, max_items: 5)
:ok
iex> Valdi.validate("hello", min_length: 3)
:ok
Validate decimal values.
Deprecated: Use validate_number/2 instead, which now supports both numbers and Decimal types.
# Instead of this (deprecated):
Valdi.validate_decimal(Decimal.new("12.5"), min: Decimal.new("10.0"))
# Use this:
Valdi.validate_number(Decimal.new("12.5"), min: Decimal.new("10.0"))
Apply validation for each array item
Validate embed types
Check if value is not included in the given enumerable. Similar to validate_inclusion/2
Checks whether a string match the given regex pattern.
iex> Valdi.validate_format("year: 2001", ~r/year:\s\d{4}/)
:ok
iex> Valdi.validate_format("hello", ~r/+/)
{:error, "does not match format"}
iex> Valdi.validate_format("hello", "h.*o")
:ok
Check if value is included in the given enumerable.
iex> Valdi.validate_inclusion(1, [1, 2])
:ok
iex> Valdi.validate_inclusion(1, {1, 2})
{:error, "given condition does not implement protocol Enumerable"}
iex> Valdi.validate_inclusion(1, %{a: 1, b: 2})
{:error, "not be in the inclusion list"}
iex> Valdi.validate_inclusion({:a, 1}, %{a: 1, b: 2})
:ok
@spec validate_length( support_length_types(), keyword() ) :: :ok | error()
Check if length of value match given conditions. Length condions are the same with validate_number/2
iex> Valdi.validate_length([1], min: 2)
{:error, "length must be greater than or equal to 2"}
iex> Valdi.validate_length("hello", equal_to: 5)
:okSupported types
listmaptuplekeywordstring
Validate list value aganst validator and return error if any item is not valid.
In case of error {:error, errors}, errors is list of error detail for all error item includes [index, message]
iex> Valdi.validate_list([1,2,3], type: :integer, number: [min: 2])
{:error, [[0, "must be greater than or equal to 2"]]}
Validate map value with given map specification. Validation spec is a map
validate_map use the key from validation to extract value from input data map and then validate value against the validators for that key.
In case of error, the error detail is a map of error for each key.
iex> validation_spec = %{
...> email: [type: :string, required: true],
...> password: [type: :string, length: [min: 8]],
...> age: [type: :integer, number: [min: 16, max: 60]]
...> }
iex> Valdi.validate_map(%{name: "dzung", password: "123456", email: "ddd@example.com", age: 28}, validation_spec)
{:error, %{password: "length must be greater than or equal to 8"}}
Validate number value
iex> Valdi.validate_number(12, min: 10, max: 12)
:ok
iex> Valdi.validate_number(12, min: 15)
{:error, "must be greater than or equal to 15"}
iex> Valdi.validate_number(Decimal.new("12.5"), min: Decimal.new("10.0"))
:okSupport conditions
equal_togreater_than_or_equal_to|mingreater_thanless_thanless_than_or_equal_to|max
Works with both regular numbers and Decimal types.
Validate value if value is not nil. This function can receive a function to dynamicall calculate required or not.
iex> Valdi.validate_required(nil, true)
{:error, "is required"}
iex> Valdi.validate_required(1, true)
:ok
iex> Valdi.validate_required(nil, false)
:ok
iex> Valdi.validate_required(nil, fn -> 2 == 2 end)
{:error, "is required"}
Validate data types.
iex> Valdi.validate_type("a string", :string)
:ok
iex> Valdi.validate_type("a string", :number)
{:error, "is not a number"}Support built-in types:
booleanintegerfloatnumber(integer or float)string|binarytuplemaparrayatomfunctionkeyworddatedatetimenaive_datetimetime
It can also check extend types
structEx:User{:array, type}: array of type