Tarams v0.4.0 Tarams View Source

Tarams provide a simpler way to define and validate data with power of Ecto.Changeset and schemaless. And Tarams is even more powerful with:

  • default function which generate value each casting time
  • custom validation functions
  • custom parse functions
  • shorter schema definition

Basic 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

A Schema is a simple map of field: options

Sample schema

  schema1 = %{
    keyword: :string
    status: [type: :string, required: true, validate: {:inclusion, ["open", "processing", "completed"]}],
    page: [type: :integer, default: 1],
    start_date: [type: :date, default: &Timex.today/0]
  }

Field options

  • If there is no options, a field can be written in short form <field_name>: <type>.

  • required is false by default, this field is used to check if a field is required or not

  • validate define how a field is validated, read section Validation for more details.

  • default set default value. It could be a value or a function, if is is a function, it will be evaluated each time parse or cast function is called.

Example

  %{
    category: [type: :string, default: "elixir"],
    end_date: [type: :date, default: &Timex.today/1]
  }
  • cast_func: custom function to cast raw value to schema type. This is cast_func spec fn(any) :: {:ok, any} | {:error, binary} By defaut, parse function uses Ecto.Changeset cast function for built-in types, with cast_func you can define your own cast function for your custom type.

    Example

    schema =
      %{
        status: [type: {:array, :string}, cast_func: fn value -> {:ok, String.split(",")} end]
      }
    Tarams.parse(schema, %{status: "processing,dropped"})

Validation

  • You can use any validation which Ecto.Changeset supports. There is a simple rule to map schema declaration with Ecto.Changeset validation function. Simply concatenate validate and validation type to get Ecto.Changeset validation function.
validate: {<validation_name>, <validation_option>}

Example

  %{status: [type: string, validate: {:inclusion, ["open", "pending"]}]}

  # is translated to
  Ecto.Changeset.validate_inclustion(changeset, :status, ["open", "pending"])
  • If your need many validate function, just pass a list to :validate option. Example
  %{status: [type: string, validate: [{validate1, otps1}, {validate2, opts2}]] }
  • You can pass a custom validation function too. Your function must follow this spec

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>}]}

Link to this section Summary

Functions

Build an Ecto schemaless schema and then do casting and validating params

Cast params to a changeset and then check if changeset.valid? = true then invoke Changeset.apply_changes and return {:ok, data}. Otherwise, return {:error, changeset}

Link to this section Functions

Specs

cast(map(), map()) :: Ecto.Changeset

Build an Ecto schemaless schema and then do casting and validating params

Specs

parse(map(), map()) :: {:ok, map()} | {:error, Ecto.Changeset.t()}

Cast params to a changeset and then check if changeset.valid? = true then invoke Changeset.apply_changes and return {:ok, data}. Otherwise, return {:error, changeset}