How to pass additional error details through fallback controller to error view?

Hi there,

I’m trying to figure out how to pass additional information about an error coming from my domain layer which maps to a more generic error, say a “401 Unauthorized”. Put more simply, I’d like the ability to send an optional error string to the fallback controller:

{:error, :unauthorized}
# or
{:error, :unauthorized, "some additional error details"}

So, in my domain layer, I have:

  def login_with_facebook(access_token) do
    case @facebook_api.me("first_name, last_name, email, gender", access_token) do
      {:json, %{"error" => %{"type" => "OAuthException", "message" => message}}} ->
        {:error, :unauthorized, message}
      {:json, %{"error" => %{"message" => message}}} ->
        {:error, :unknown, message}
      {:json, user_data} ->
        # do stuff
    end
  end

Then, in my controller:

  def facebook(conn, %{"access_token" => access_token}) do
    with {:ok, %User{} = user} <- Domain.login_with_facebook(access_token) do
      conn
      |> put_status(:created)
      |> render(UserView, "show.json", user: user)
    end
  end

I’m assuming I’d need to create an additional function in the fallback controller to handle this additional but optional message but it feels a bit awkward:

  def call(conn, {:error, :unauthorized}) do
    conn
    |> put_status(:unauthorized)
    |> render(RevealWeb.ErrorView, :"401")
  end

  def call(conn, {:error, :unauthorized, error}) do
    conn
    |> put_status(:unauthorized)
    |> render(RevealWeb.ErrorView, :"401", error: error)
  end

Curious to know, is there’s a better way to achieve this?

Thanks!

1 Like

This is the answer :slight_smile:

As you showed, you need to expose the error message as part of your return value and then define a clause to handle it in the fallback controller. I wouldn’t consider this awkward and you can compose the fallback controller clauses to accept an error message or not with the same 401 status/template render. Hope that helps!

2 Likes

Sweet, thanks! I wasn’t sure if modifying the conn was possibly preferred or if maybe there was an alternative that I just wasn’t aware of. Being relatively new to Phoenix and Elixir, it’s nice to know the solution is approved of!

1 Like