Magik.Contract (Magik v0.11.0) View Source
Contract helps to define a contract for function call, and do validate contract data with:
- Validate type
- Validate required
- Validate
in|not_inenum - Valiate length for
string,enumerable - Validate number
- Validate string against regex pattern
- Custom validation function
- With support nested type
- Clean not allowed fields
@update_user_contract %{
user: [type: User, required: true],
attributes: [type: %{
email: [type: :string],
status: [type: :string, in: ~w(active in_active)]
age: [type: :integer, number: [min: 10, max: 80]],
}, required: true]
}
def update_user(contract) do
with {:ok, validated_data} do
validated_data.user
|> Ecto.Changeset.change(validated_data.attributes)
|> Repo.update
else
{:error, errors} -> IO.inspect(errors)
end
end
NOTES: Contract only validate data, not cast data
Support validation
Type
Support built-in types;
booleaninteger,floatnumber- string or integerstringtuplemaparraylistatomfunctionkeywordstructarrayof type
Example:
Magik.Contract.validate(%{name: "Bluz"}, %{name: [type: :string]})
Magik.Contract.validate(%{id: 123}, %{name: [type: :integer]})
Magik.Contract.validate(%{id: 123}, %{name: [type: {:array, :integer}]})
Magik.Contract.validate(%{user: %User{}}, %{user: [type: User]})
Magik.Contract.validate(%{user: %User{}}, %{user: [type: {:array: User}]})Required
Magik.Contract.validate(%{name: "Bluz"}, %{name: [type: :string, required: true]})Allow nil
Magik.Contract.validate(
%{name: "Bluz", email: nil},
%{
name: [type: :string],
email: [type: string, allow_nil: false]
})Inclusion/Exclusion
Magik.Contract.validate(
%{status: "active"},
%{status: [type: :string, in: ~w(active in_active)]}
)
Magik.Contract.validate(
%{status: "active"},
%{status: [type: :string, not_in: ~w(banned locked)]}
)Format
Validate string against regex pattern
Magik.Contract.validate(
%{email: "Bluzblu@gm.com"},
%{name: [type: :string, format: ~r/.+?@.+.com/]
})Number
Validate number value
Magik.Contract.validate(
%{age: 200},
%{age: [type: :integer, number[greater_than: 0, less_than: 100]]
})Support conditions
equal_togreater_than_or_equal_to|mingreater_thanless_thanless_than_or_equal_to|max
Length
Check length of list, map, string, keyword, tuple
Supported condtions are the same with Number check
Magik.Contract.validate(
%{title: "Hello world"},
%{age: [type: :string, length: [min: 10, max: 100]]
})Custom validation function
Invoke given function to validate value. The function signature must be
func(field_name ::(String.t() | atom()), value :: any(), all_params :: map()) :: :ok | {:error, message}Magik.Contract.validate(
%{email: "blue@hmail.com"},
%{email: [type: :string, func: &validate_email/3]})
def validate_email(_name, email, _params) do
if Regex.match?(~r/[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,4}$/, email) do
:ok
else
{:error, "not a valid email"}
end
endNested map
Nested map declaration is the same.
data = %{name: "Doe John", address: %{city: "HCM", street: "NVL"} }
schema = %{
name: [type: :string],
address: [type: %{
city: [type: :string],
street: [type: :string]
}]
}
Magik.Contract.validate(data, schema)Nested list
data = %{name: "Doe John", address: [%{city: "HCM", street: "NVL"}] }
address = %{ city: [type: :string], street: [type: :string] }
schema = %{
name: [type: :string],
address: [type: {:array, address}]
}
Magik.Contract.validate(data, schema)
Link to this section Summary
Functions
Validate data against given schema
Link to this section Functions
Specs
Validate data against given schema