Tarams

Tarams provides a simple way for parsing request params with predefined schema

Why Tarams

- Reduce code boilerplate
- Shorter schema definition
- Default function which generate value each casting time
- Custom validation functions
- Custom parse functions

Installation

Available in Hex, the package can be installed by adding tarams to your list of dependencies in mix.exs:

def deps do
[
{:tarams, "~> 0.4.0"}
]
end

Usage

@index_params_schema %{
keyword: :string,
status: [type: string, required: true],
group_id: [type: :integer, validate: {:number, [greater_than: 0]}]
}
def index(conn, params) do
with {:ok, better_params} <- Tarams.parse(@index_params_schema, params) do
# do anything with your params
else
{:error, changset} -> # return params error
end
end

Default value

You can define a default value for a field if it's missing from the params.

schema = %{
status: [type: :string, default: "pending"]
}

Or you can define a default value as a function. This function is evaluated when Tarams.parse gets invoked.

schema = %{
date: [type: :utc_datetime, default: &Timex.now/0]
}

Custom cast function

By default Tarams uses Ecto.Changeset to cast built-in types. If you don't want to use default casting functions, or you want define casting function for custom type, tarams provide cast_func option to define a custom cast function. This is cast_func spec fn(any) :: {:ok, any} | {:error, binary}

If cast_func returns {:ok, value}, this value is added to changeset. If it returns {:error, message}, error message is added to changeset errors.

def my_array_parser(value) do
if is_binary(value) do
ids =
String.split(value, ",")
|> Enum.map(&String.to_integer(&1))
{:ok, ids}
else
{:error, "Invalid string"
end
end
schema = %{
user_id: [type: {:array, :integer}, cast_func: &my_array_parser/1]
}
Tarams.parse(schema, %{user_id: "1,2,3"})

This is a demo parser function.

Validation

validate: {<validation_name>, <validation_option>}

Example

%{status: [type: string, validate: {:inclusion, ["open", "pending"]}]}
# is translated to
Ecto.Changeset.validate_inclustion(changeset, :status, ["open", "pending"])
%{status: [type: string, validate: [{validate1, otps1}, {validate2, opts2}]] }

fn(Ecto.Changeset, atom, list) :: Ecto.Changeset

Example

def custom_validate(changeset, field_name, opts) do
# your validation logic
end
%{status: [type: :string, validate: {&custom_validate/2, <your_options>}]}

Contributors

If you find a bug or want to improve something, please send a pull request. Thank you!