phcurado
Parameter - Simplified definition, serialization, deserialization and validation of params
Parameter is a library for dealing with parameter serialization, deserialization and validation following a structure very similar to Ecto schema.
The main motivation for creating this is to have more options when loading external parameters and convert it to plain elixir maps or structure. It can load the data to a map or struct, transform external data keys to elixir keys, perform validations and dump the data.
The idea is to create a schema that models the data you need to load on your elixir application. The “key” field on the schema is useful to map keys that comes with a different format of your schema keys. For example when external data have camelCase keys and you want to use snake_case.
As an example imagine you are making and http request to a rest API to fetch a single user, this is how you can model the User schema:
defmodule User do
use Parameter.Schema
alias Parameter.Validators
param do
field :first_name, :string, key: "firstName", required: true
field :last_name, :string, key: "lastName"
field :email, :string, validator: &Validators.email(&1)
has_one :address, Address do
field :city, :string, required: true
field :street, :string
field :number, :integer
end
end
end
And this is how the external data could look like:
params = %{
"firstName" => "John",
"lastName" => "Doe",
"email" => "john@email.com",
"address" => %{"city" => "New York", "street" => "Broadway"}
}
Now this params can be deserialized using the load/2 function
iex> Parameter.load(User, params)
{:ok, %{
first_name: "John",
last_name: "Doe",
email: "john@email.com",
address: %{city: "New York", street: "Broadway"}
}}
the camelCase keys were converted to snake_case keys as per schema definition. If the external data already have the same key type as the schema definition this param can be ignored.
It also possible to load the schema as structure:
iex> Parameter.load(User, params, struct: true)
{:ok, %User{
first_name: "John",
last_name: "Doe",
email: "john@email.com",
address: %User.Address{city: "New York", street: "Broadway", number: nil}
}}
Also can be used on Phoenix APIs that needs to validate parameters before sending it to the context module.
defmodule MyProjectWeb.UserController do
use MyProjectWeb, :controller
import Parameter.Schema
alias MyProject.Users
param UserParams do
field :first_name, :string, required: true
field :last_name, :string, required: true
end
def create(conn, params) do
with {:ok, user_params} <- Parameter.load(__MODULE__.UserParams, params),
{:ok, user} <- Users.create_user(user_params) do
render(conn, "user.json", %{user: user})
end
end
end
There are plenty of more options available as built in validators (or possibility for creating custom ones), custom types, error handling, unknown options that comes from external data and serializing (dump) the data.
Most Liked
phcurado
Parameter 0.8.0 version released ![]()
Now supports creating schemas without relying on any macro API.
Example on how it works:
## Create your runtime schema
schema = %{
first_name: [key: "firstName", type: :string, required: true],
address: [required: true, type: {:has_one, %{street: [type: :string, required: true]}}],
phones: [type: {:has_many, %{number: [type: :string, required: true], country_code: [key: "countryCode", type: :integer, required: true]}}]
}
# Compile the schema (it also performs validation)
compiled_schema = Parameter.Schema.compile!(schema)
# Now suppose these are the parameters coming from an external data
params = %{
"firstName" => "John",
"address" => %{"street" => "some street"},
"phones" => [
%{"number" => "123456789", "countryCode" => 123}
]
}
# Load the parameters against the schema
Parameter.load(compiled_schema, params)
{:ok,
%{
address: %{street: "some street"},
first_name: "John",
phones: [%{country_code: 123, number: "123456789"}]
}}
It’s also possible to have the same compile time guarantees from the Macro API by using module attributes:
defmodule UserParams do
alias Parameter.Schema
@schema %{
first_name: [key: "firstName", type: :string, required: true],
last_name: [key: "lastName", type: :string, required: true]
} |> Schema.compile!()
def load(params) do
Parameter.load(@schema, params)
end
end
params = %{"firstName" => "John", "lastName" => "Doe"}
UserParams.load(params)
{:ok, %{first_name: "John", last_name: "Doe"}}
phcurado
Parameter 0.5.0 version released.
New types introduced to offer more options when loading/dumping data:
0.5.0 - Enum type
Enum type is now supported. This type is useful for translating external data enum definitions to internal values.
Example of having a UserParam schema:
defmodule MyApp.UserParam do
use Parameter.Schema
enum Status do
value "active", as: :active
value "pendingRequest", as: :pending_request
end
param do
field :first_name, :string, key: "firstName"
field :status, MyApp.UserParam.Status
end
end
We can load or dump the data with the enum value, automatically converted to it’s definition:
iex> Parameter.load(MyApp.UserParam, %{"firstName" => "John", "status" => "active"})
{:ok, %{first_name: "John", status: :active}}
# or dumping data the atom value will be converted:
...> Parameter.dump(MyApp.UserParam, %{first_name: "John", status: :pending_request})
{:ok, %{"firstName" => "John", "status" => "pendingRequest"}}
It can work also with integer values since some APIs use numbers for enum representation:
enum Status do
value 1, as: :active
value 2, as: :pending_request
end
and load/dump will give the following results:
iex> Parameter.load(MyApp.UserParam, %{"firstName" => "John", "status" => 1})
{:ok, %{first_name: "John", status: :active}}
# or dumping data the atom value will be converted:
...> Parameter.dump(MyApp.UserParam, %{first_name: "John", status: :pending_request})
{:ok, %{"firstName" => "John", "status" => 2}}
check all the available options for declaring and using enums here.
0.4.0 - Decimal type
decimal type supported, it’s very simple to add on your schema.
For example having a Payment schema with amount field that should be parsed as decimal:
defmodule MyApp.Payment do
use Parameter.Schema
param do
field :amount, :decimal
end
end
load the data using the schema definition:
iex> Parameter.load(Payment, %{"amount" => 10.50})
{:ok, %{amount: #Decimal<10.5>}}
And add the optional decimal dependency to be able to work with this type.
phcurado
Parameter 0.11.0 version released ![]()
Some small improvements:
- Support for
on_load/2andon_dump/2functions in field definition which gives the possibility to customize load and dump behaviour. ignore_nilandignore_emptyoption added for customizing the behaviour when receivingnilor empty""fields.- Supports for deep nested types when using
maporarraycomposite types. - Test coverage is now 100%

Changelog here
Popular in Announcing
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









