ValidateQuery - Validate and filter query parameters

When working on a JSON-API-like API, the results are often determined by the query parameters. For example, if you have a users endpoint and you want to include both the users’ profile and company, you might use include=profile,company.

I found dealing with these types of query parameters to be outside of the scope of Ecto / changesets, and instead created this plug which allows you to define for any query parameter the allowed values, cast and default value. Here’s an example of it’s usage:

defmodule MyApp.UserController do
  plug(ValidateQuery,
    include: {["company", "profile"], :list},
    filter: [name: {:any}, only_active: {:any, :boolean, true}],
  )

  def index(conn, _params) do
    # params["filter"] should have _at least_ %{"only_active" => true} if nothing was given.
    # return response
  end
end

Here, we define 2 query parameters:

  • include: A list with either of the two values: "company" or "profile". The :list atom specifies that the value should be cast to a list. In this case this means that either include=profile,company or include[]=profile&include[]=company is accepted.
  • filter: A map with 2 keys, name and only_active, in which name may have any value and only_active should be a boolean, defaults to true.

An example of a query that is accepted with this definition:

/users?filter[only_active]=false&filter[name]=john&include=profile&filter[age]=30

%Plug.Conn{params: {"include" => ["profile"], "filter" => %{"only_active" => false, "name" => "john"}}}

As you can see, the filter[age] has been filtered out of the parameters.

Any keys outside of include and filter are kept as is (so they won’t be filtered out).

1 Like