How do I clean up this code from an example in the PragProg elixir course?

Have now cleaned up my typos, incorporated kartheeks suggestion of using defaults (which helped clarify the code quite a bit), and tested the result. Notice how using function calls eliminates the need for conditionals.

defmodule JsonAPI do
  @c %{"posts"=>100,"comments"=>500,"albums"=>100,"photos"=>5000,"todos"=>200,"users"=>10}
  @b "https://jsonplaceholder.typicode.com/"

  def query(c, id \\ 0, keys \\ []),       do: chk_input(c, id) |> request({c, id, keys})

  defp chk_input(c, id) ,                  do: is_cat(c in Map.keys(@c), c, id)

  defp is_cat(true, c, id),                do: in_range(id <= @c[c], c)
  defp is_cat(_,    c, _ ),                do: {:error, "'#{c}' is invalid"}

  defp in_range(true, _ ),                 do: :ok
  defp in_range( _  , c ),                 do: {:error, "'#{c}' max id: #{@c[c]}"}

  defp request(:ok, {c, id, keys}),        do: lookup(c, id) |> reply(keys)
  defp request({:error, msg},  _   ),      do: msg

  defp lookup(c, 0),                       do: HTTPoison.get("#{@b}#{c}")
  defp lookup(c, i),                       do: HTTPoison.get("#{@b}#{c}/#{to_string(i)}")

  defp reply({:error, reason }, _ ),              do: {:error,    reason}
  defp reply({_,%{status_code: 200,body: b}},[]), do: {:ok,       parse(b) }
  defp reply({_,%{status_code: 200,body: b}},k),  do: {:ok,       parse(b) |> get_in(k) }
  defp reply({_,%{status_code:  s, body: b}},_),  do: {:error, s, parse(b) |> get_in(["message"])}

  defp parse(body),                        do: Poison.Parser.parse!(body, %{})

  end
type or paste code here
1 Like

Much nicer!!

One more cleanup tweak:

defmodule JsonAPI do
  @c %{"posts"=>100,"comments"=>500,"albums"=>100,"photos"=>5000,"todos"=>200,"users"=>10}
  @b "https://jsonplaceholder.typicode.com/"

  def query(c, id \\ 0, keys \\ []), do: chk_input(c, id) |> request({c, id, keys})

  defp chk_input(c, id),             do: is_cat(c in Map.keys(@c), c, id)

  defp is_cat(true, c, id),          do: in_range(id <= @c[c], c)
  defp is_cat(_,    c, _ ),          do: {:error, "'#{c}' is invalid"}
  defp in_range(true, _ ),           do: :ok
  defp in_range( _  , c ),           do: {:error, "#{c} max id: #{@c[c]}"}

  defp request( :ok, {c, id, keys}), do: lookup(c, id) |> reply(keys)
  defp request({:error, msg},  _  ), do: msg

  defp lookup(c, 0),                 do: HTTPoison.get("#{@b}#{c}")
  defp lookup(c, i),                 do: HTTPoison.get("#{@b}#{c}/#{to_string(i)}")

  defp reply({:error, reason }, _ ),              do: {:error,  reason}
  defp reply({_,%{status_code: 200,body: b}},[]), do: {:ok,     parse(b) }
  defp reply({_,%{status_code: 200,body: b}},k),  do: {:ok,     filter(b, k) }
  defp reply({_,%{status_code:  s, body: b}},_),  do: {:error,s,filter(b,["message"])}

  defp filter(body, keys),           do: parse(body) |> get_in(keys)
  defp parse(body),                  do: Poison.Parser.parse!(body, %{})
  end
2 Likes

Very nice indeed. Gives a whole new aspect to the problem.

1 Like