Need help with params?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

271 Stars 27 Forks Apache License 2.0 92 Commits 8 Opened issues


Easy parameters validation/casting with Ecto.Schema, akin to Rails' strong parameters.

Services available


Need anything else?

Contributors list


Easily define parameter structure and validate/cast with Ecto.Schema Build Status help maintain this lib


Available in Hex, the package can be installed as:

  1. Add params to your list of dependencies in
def deps do
  [{:params, "~> 2.0"}]


If you've been doing Ecto based applications lately, you know Ecto provides a very easy way to populate structs with data coming from request parameters, validating and casting their values along the way.

All this thanks to the Ecto.Schema and Ecto.Changeset modules. The first specifies the fields your model has (typically the same as your db table) and the later provides an easy way to convert potentially unsafe data and validate stuff via changesets.

So for example, in a typical Phoenix application, a

model would look like:
defmodule MyApp.User do
   use MyApp.Web, :model

schema "users" do field :name, :string field :age, :integer end

@required [:name] @optional [:age]

def changeset(changeset_or_model, params) do cast(changeset_or_model, params, @required ++ @optional) |> validate_required(@required) end end

Normally, changesets are related to some data that will be persisted into a database, and your controller would use the

method like:
# UserController.ex
def create(conn, params) do
  ch = User.changeset(%User{}, params)
  if ch.valid? do

However, you can use

for validating/casting data that wont necessarily be persisted into a database. All you need is just specify a module and define your schema, Ecto.Changeset will be happy to work with it.

This comes handy when you have certain parameter structure you want to enforce for example when creating a REST API.

Some Rails developers might be right now wondering where their strong parameters can be defined. On Elixir land, there's no need for such a thing, as we will see, just using an

can be much more flexible. Using schemas allows not only specifing which fields we want, but changesets let use type cast, perform validations on values, etc.

So, for example, suppose your Phoenix based API performs a search for kittens looking for a home and expects something like:

  "breed": "Russian Blue",
  "age_min": 0,
  "age_max": 5,
  "near_location": {
     "latitude": 92.1,
     "longitude": -82.1

You'd like to validate that your controller has received the correct params structure, all you need to do is create a couple of modules:

defmodule MyApi.Params.Location
  use Ecto.Schema
  import Ecto.Changeset

@required ~w(latitude longitude) @optional ~w()

schema "location params" do field :latitude, :float field :longitude, :float end

def changeset(ch, params) do cast(ch, params, @required ++ @optional) |> validate_required(@required) end end

defmodule MyAPI.Params.KittenSearch use Ecto.Schema import Ecto.Changeset

@required ~w(breed) @optional ~w(age_min age_max)

schema "params for kitten search" do field :breed, :string field :age_min, :integer field :age_max, :integer embeds_one :near_location, Location end

def changeset(ch, params) do cast(ch, params, @required ++ @optional) |> validate_required(@required) |> cast_embed(:near_location, required: true) end end

On your controller:

def search(conn, params) do alias MyAPI.Params.KittenSearch changeset = KittenSearch.changeset(%KittenSearch{}, params) if changeset.valid? do ... end

That would allow you to take only valid params as you'd normally have with any other Ecto.Schema module.

However it's still a lot of code, most of it defining the the changeset, specifying the optional and required fields, etc.

Params is just a simple Ecto.Schema wrapper for reducing all this boilerplate, while still leting you create custom changesets for parameter processing.


The previous example could be written like:

defmodule MyAPI.KittenController do

use Params

defparams kitten_search %{ breed!: :string, age_max: :integer, age_min: [field: :integer, default: 1], near_location!: %{ latitude!: :float, longitude!: :float }, tags: [:string] }

def index(conn, params) do changeset = kitten_search(params) if changeset.valid? do search = changeset IO.puts search.near_location.latitude ... end end


macro generates a module for processing a params schema

By default all fields are optional. You can mark required fields by ending them with a

, of course the bang is removed from the field definition and is only used to mark which fields are required by default.

You can also create a module and define your schema or custom changesets in it:

defmodule UserSearch do
  use Params.Schema, %{name: :string, age: :integer}
  import Ecto.Changeset, only: [cast: 3, validate_inclusion: 3]

def child(ch, params) do cast(ch, params, ~w(name age)) |> validate_inclusion(:age, 1..6) end end

defmodule MyApp.UserController do

def index(conn, params) do changeset = UserSearch.from(params, with: &UserSearch.child/2) if changeset.valid? do # age in 1..6 end


The and Params.to_map can be useful for obtaining a struct or map from a changeset.

Note that
have different behaviour:
returns a struct which will include all valid params.
returns a map that only includes the submitted keys and keys with default values:
defmodule UserUpdateParams do
  use Params.Schema, %{
    name: :string,
    age: :integer,
    auditlog: [field: :boolean, default: true]

changeset = UserUpdateParams.from(%{name: "John"}) # => %UserUpdateParams{name: "John", age: nil, auditlog: true} Params.to_map(changeset) # => %{name: "John", auditlog: true}

API Documentation

API Documentation


Here's a list of awesome people who have contributed code to this project.

If you find a bug or want to improve something, please send a pull-request. Thank you!

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.