Para (Para v0.2.1)

Para is an Elixir library that provides structured and declarative way to parse and validate parameters.

Para uses Ecto under the hood and therefore inherits most of its utilities such as changeset and built-in validators.

Usage

Let's imagine that you have a controller named Web.UserController and wanted to validate the parameters for its :create and :update actions

First, let's define your parameters schema

defmodule Web.UserPara do
  use Para

  validator :create do
    required :name, :string
    required :age, :integer
    required :email, :string
    optional :phone, :string
  end

  validator :update do
    required :name, :string
    required :age, :integer
    required :email, :string
    optional :phone, :string
  end
end

You can now use this module as a validator in your controller

defmodule Web.UserController do
  use Web, :schema
  alias Web.UserPara

  def create(conn, params) do
    with {:ok, data} <- UserPara.validate(:create, params) do
      # ...
    end
  end
end

Inline validators

Inline validator is a convenient way to validate your fields. This is especially useful when you need to perform some basic validation using Ecto.Changeset's built-in validators.

defmodule UserPara do
  use Para

  validator :update do
    required :name, :string, validator: {:validate_length, [min: 3, max: 100]}
  end
end

You can also use custom inline validators by supplying the function name as an atom. Custom inline validator will receive changeset and the original params as the arguments.

defmodule UserPara do
  use Para

  validator :update do
    required :age, :string, validator: :validate_age
  end

  def validate_age(changeset, params) do
    # ...
  end
end

Callback validator

Sometimes, you might want to use custom validators or need to perform additional data manipulations. For this, you can use the callback/1 macro.

The callback/1 macro will always be the last function to be called after the validator has parsed and validated the parameters.

defmodule Web.UserPara do
  use Para

  validator :create do
    required :name, :string
    required :age, :integer
    required :email, :string
    optional :phone, :string
    callback :create_validators
  end

  def create_validators(changeset, params) do
    changeset
    |> format_email(params)
    |> format_phone(params)
    |> validate_age()
  end

  def format_email(changeset, params) do
    # ...
  end

  def format_phone(changeset, params) do
    # ...
  end

  def validate_age(changeset) do
    # ...
  end
end

Link to this section Summary

Functions

Define custom callback to perform any additional parsing or validation to the processed changeset or parameters

Define an embedded array of maps field

Define an embedded map field

Define a validator schema with an action name and field definitions.

Link to this section Types

Specs

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

Link to this section Functions

Link to this macro

callback(name)

(macro)

Define custom callback to perform any additional parsing or validation to the processed changeset or parameters

Link to this macro

embeds_many(name, list)

(macro)

Define an embedded array of maps field

Link to this macro

embeds_one(name, list)

(macro)

Define an embedded map field

Link to this macro

optional(name, type \\ :string, opts \\ [])

(macro)

Define an optional field.

Similar to required/3, it also accepts the same Options

Link to this macro

required(name, type \\ :string, opts \\ [])

(macro)

Define a required field.

Options

  • :default - Assign a default value if the not set by input parameters

  • :validator - Define either one of the built-in Ecto.Changeset's validators or use your own custom inline validator. Refer: Custom inline validator

  • :droppable - Drop the field when the key doesn't exist in parameters. This is useful when you need to perform partial update by leaving out certain fields.

Custom inline validator

You can define your own validator as such:

def validate_country(changeset, field) do
  # ...
end

Then use it as an inline validator for your field

validator :create do
  required :country, :string, [validator: :validate_country]
end
Link to this macro

validator(name, list)

(macro)

Define a validator schema with an action name and field definitions.

This will generate a new function called validate/2 with the action name and params as the arguments.

iex> defmodule UserPara do
...>   use Para
...>
...>   validator :create do
...>     required :name
...>   end
...> end
...>
...> UserPara.validate(:create, %{"name" => "Syamil MJ"})
{:ok, %{name: "Syamil MJ"}}