Best inputs for searching methods (e.g. list_items)

This is more of a general question, but it really hit home as I read through the “Craft GraphQL APIs” Absinthe book. I noticed this pattern:

defmodule MyContext do
    def list_items(args) do 
      args
      |> Enum.reduce(Item, fn 
        {:order, order}, query ->
          query |> order_by({^order, :name}) 
        {:filter, filter}, query ->
          query |> filter_with(filter) 
      end)
      |> Repo.all
    end

    defp filter_with(query, filter) do
      Enum.reduce(filter, query, fn
        {:name, name}, query ->
          from q in query, where: ilike(q.name, ^"%#{name}%")
        {:priced_above, price}, query ->
          from q in query, where: q.price >= ^price
        {:priced_below, price}, query ->
          from q in query, where: q.price <= ^price
        {:category, category_name}, query ->
          from q in query,
            join: c in assoc(q, :category),
            where: ilike(c.name, ^"%#{category_name}%")
        {:tag, tag_name}, query ->
          from q in query,
            join: t in assoc(q, :tags),
            where: ilike(t.name, ^"%#{tag_name}%")
      end)
    end
end

That seems like a brilliant and expressive way of structuring dynamic search criteria, and it has the benefit of tying in well to the Absinthe resolvers, but my questions are:

  1. What exactly IS that function expecting? Is it something like this: args = [{name: "Some name"}, {order: :asc}]
  2. How could you “feed” into this structure with a standard REST endpoint? I’m having a hard time wrapping my head around how you could send a JSON body (let alone standard form-encoded inputs) that would properly represent linked lists.
  3. I have noticed that for standard Phoenix controllers, the submitted params arrives as a map using binary keys, but here within the GraphQL resolves, the inputs use atom keys. Would it be a good idea to normalize both forms of input?

Thanks – sorry if this is rambling.