Asimov
Filtering API results
Hi all,
I am learning how to create a basic API with Phoenix (I know, I do not need Phoenix, but I wanted to see how it is actually done). Everything works well but I have not been able to wrap my head around the process to filter results. For instance, my API JSON return is like this:
{
"data": {
"active": true,
"carmaker": "Simca",
"id": 1,
"owner": "James Bon",
"plate": 345671
}
}
It all goes well if I simply do:
GET /api/customers/ or GET /api/customers/1. But I want to be able to do GET /api/customers?carmaker=carmaker_name
What I have so far is:
router.ex:
defmodule NukakApiWeb.Router do
use NukakApiWeb, :router
# use Pow.Phoenix.Router
pipeline :api do
plug :accepts, ["json"]
plug NukakApiWeb.ApiAuthPlug, otp_app: :nukak_api
end
scope "/api", NukakApiWeb do
pipe_through [:api]
resources "/customers", CustomerController, only: [:show, :index]
# resources "/customers/:id", CustomerController, :show
end
end
customer_controller.ex:
defmodule NukakApiWeb.CustomerController do
use NukakApiWeb, :controller
# I know the following line should better go on a different file. Just adding it here for simplicity.
def get_customer!(id), do: Repo.get!(Customer, id)
def list_customers do
Repo.all(Customer)
end
def index(conn, _params) do
customers = list_customers()
render(conn, "index.json", customers: customers)
end
def show(conn, %{"id" => id}) do
customer = get_customer!(id)
render(conn, "show.json", customer: customer)
end
customer_view.ex:
defmodule NukakApiWeb.CustomerView do
use NukakApiWeb, :view
alias NukakApiWeb.CustomerView
def render("index.json", %{customers: customers}) do
%{data: render_many(customers, CustomerView, "customer.json")}
end
def render("show.json", %{customer: customer}) do
%{data: render_one(customer, CustomerView, "customer.json")}
end
def render("customer.json", %{customer: customer}) do
%{id: customer.id,
name: customer.name,
plate: customer.plate,
carmaker: customer.carmaker,
active: customer.active}
end
end
I tried following this guy idea but I got lost in the assign() function:
def valid_filters(conn, params) do
filters = Enum.filter(conn.params, fn({k, v}) ->
Enum.member?(params, k)
end)
conn |> assign(:filters, filters)
end
There is the json_api_query_builder package but it does not seem to be compatible with ecto 3.
Anyway, if anybody can give me a hint on what is it that I have to do I would really appreciate it.
Thanks very much!
Marked As Solved
chasers
You’re close! Add these to your CustomerController:
import Ecto.Query
# Correct, this should go in the `Customer` context along with the `Ecto.Query` import.
def get_customers_by(keyword) do
query =
from c in Customer,
where: keyword,
select: c
Repo.all(query)
end
def show(conn, %{"carmaker" => carmaker}) do
customers = get_customers_by(carmaker: carmaker)
response = Jason.encode!(customers)
# This is what I've done, but I don't know views at all.
conn
|> put_resp_content_type("application/json")
|> send_resp(200, response)
end
Validating filters is a good idea but random filters just won’t match anything currently. Do you want people to be able to build queries dynamically via the API?
Looks cool but once you get the hang of it building an API like this is fun and quick to do yourself, plus you’ll get to know Phoenix and Ecto much better. Plus you may not want people doing dynamic queries ![]()
Popular in Questions
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









