Data validation in Elixir
The package can be installed by adding litmus
to your list of dependencies in
mix.exs
:
def deps do
[
{:litmus, "~> 0.6.0"}
]
end
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
}
}
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]}}
Litmus.validate(%{}, schema)
# => {:error, "id is required"}
Litmus currently supports the following types.
Litmus.Type.Any
Litmus.Type.Boolean
Litmus.Type.DateTime
Litmus.Type.List
Litmus.Type.Number
Litmus.Type.String
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
.
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