Asimov

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

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 :man_shrugging:

Last Post!

Asimov

Asimov

Thanks very much @chasers, this is of great help!

Where Next?

Popular in Questions Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New

Other popular topics Top

jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40165 209
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement