1.6 KiB · text History dc2edab
defmodule DiogramosWeb.Api.FallbackController do
  @moduledoc """
  Translates the error tuples the `Diogramos.Diagrams` and
  `Diogramos.Accounts` contexts return into the shared JSON error shape.
  """
  use Phoenix.Controller, formats: [:json]

  alias DiogramosWeb.Api.ErrorJSON

  def call(conn, {:error, :forbidden}) do
    render_error(conn, :forbidden, "forbidden", "You don't have access to that.")
  end

  def call(conn, {:error, :not_found}) do
    render_error(conn, :not_found, "not_found", "Not found.")
  end

  def call(conn, nil) do
    render_error(conn, :not_found, "not_found", "Not found.")
  end

  def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
    conn
    |> put_status(:unprocessable_entity)
    |> put_view(json: ErrorJSON)
    |> render(:error, %{
      code: "unprocessable",
      message: "The request was not valid.",
      details: changeset_details(changeset)
    })
  end

  def call(conn, {:error, reason}) when is_atom(reason) do
    render_error(conn, :unprocessable_entity, to_string(reason), humanize(reason))
  end

  defp render_error(conn, status, code, message) do
    conn
    |> put_status(status)
    |> put_view(json: ErrorJSON)
    |> render(:error, %{code: code, message: message})
  end

  defp changeset_details(changeset) do
    Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} ->
      Regex.replace(~r"%{(\w+)}", msg, fn _, key ->
        opts |> Keyword.get(String.to_existing_atom(key), "") |> to_string()
      end)
    end)
  end

  defp humanize(reason) do
    reason |> to_string() |> String.replace("_", " ") |> String.capitalize() |> Kernel.<>(".")
  end
end