Data validation in Elixir
Installation
The package can be installed by adding litmus to your list of dependencies in
mix.exs:
def deps do [ {:litmus, "~> 1.0.2"} ] end
Usage
Litmus validates data against a predefined schema with the Litmus.validate/2
function.
If the data is valid, the function returns {:ok, data}. The data returned
will be coerced according to the provided schema.
If the data passed does not follow the rules defined in the schema, the
function returns {:error, error_message}. It will also return an error when
receiving a field that has not been specified in the provided schema.
schema = %{ "id" => %Litmus.Type.Any{ required: true }, "username" => %Litmus.Type.String{ min_length: 6, required: true }, "pin" => %Litmus.Type.Number{ min: 1000, max: 9999, required: true }, "new_user" => %Litmus.Type.Boolean{ truthy: ["1"], falsy: ["0"] }, "account_ids" => %Litmus.Type.List{ max_length: 3, type: :number }, "remember_me" => %Litmus.Type.Boolean{ default: false } } params = %{ "id" => 1, "username" => "user@123", "pin" => 1234, "new_user" => "1", "account_ids" => [1, 3, 9] } Litmus.validate(params, schema) # => {:ok, # %{ # "id" => 1, # "new_user" => true, # "pin" => 1234, # "username" => "user@123", # "account_ids" => [1, 3, 9], # "remember_me" => false # } # } Litmus.validate(%{}, schema) # => {:error, "id is required"}
Supported Types
Litmus currently supports the following types.
Litmus.Type.AnyLitmus.Type.BooleanLitmus.Type.DateTimeLitmus.Type.ListLitmus.Type.NumberLitmus.Type.String
Plug Integration
Litmus comes with a Plug for easy integration with Plug's built-in router. You can automatically validate query
parameters and body parameters by passing the litmus_query and litmus_body private options to each route. When
declaring the plug you must include a on_error/2 function to be called when validation fails. It is recommended that
you initialize this Plug between the :match and :dispatch plugs. If you want processing to stop on a validation
error, be sure to halt the request with Plug.Conn.halt/1.
Example
defmodule MyRouter do use Plug.Router plug(Plug.Parsers, parsers: [:urlencoded, :multipart]) plug(:match) plug(Litmus.Plug, on_error: &__MODULE__.on_error/2) plug(:dispatch) @schema %{ "id" => %Litmus.Type.Number{ required: true } } get "/test", private: %{litmus_query: @schema} do Plug.Conn.send_resp(conn, 200, "items") end post "/test", private: %{litmus_body: @schema} do Plug.Conn.send_resp(conn, 200, "items") end def on_error(conn, error_message) do conn |> Plug.Conn.send_resp(400, error_message) |> Plug.Conn.halt() end end