litmus
litmus copied to clipboard
Data schema validation in Elixir
Litmus
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