Skip to content

Using action_fallback in controllers

Joel Meador edited this page Jun 8, 2026 · 1 revision

I have a lot of common error code in controllers and nested case statements, how can I reduce and reuse this code?

You can reuse common error handling in controllers with action_fallback.

Remember that the with statement has a default else clause that returns anything that fails to pattern match, so the first :error tuple will bounce out of the with and up to your fallback controller.

Let's say we have an order controller that looks up an order by id and then validates the current user can view it. We can set this up with a with statement. We won't handle any errors in the OrderController because the fallback controller will pick up on that.

defmodule Web.OrderController do
  use Web, :controller

  action_fallback Web.FallbackController

  def show(conn, %{"id" => id}) do
    %{current_user: user} = conn.assigns

    with {:ok, order} <- Orders.get(id),
         {:ok, order} <- Orders.authorize(order, user) do
      conn
      |> assign(:order, order)
      |> render("show.html")
    end
  end
end

Now we have a product controller to look up products, this will also reuse the fallback controller for a 404 page.

defmodule Web.ProductController do
  use Web, :controller

  action_fallback Web.FallbackController

  def show(conn, %{"id" => id}) do
    with {:ok, product} <- Products.get(id)do
      conn
      |> assign(:product, product)
      |> render("show.html")
    end
  end
end

And finally our fallback controller is set up with any errors it can handle in call/2 functions. The second argument is the error that a controller action returns.

defmodule Web.FallbackController do
  use Web, :controller

  def call(conn, {:error, :not_found}) do
    conn
    |> put_status(404)
    |> put_view(Web.ErrorView)
    |> render(:404)
  end

  def call(conn, {:error, :not_authorized}) do
    conn
    |> put_status(401)
    |> put_view(Web.ErrorView)
    |> render(:401)
  end
end

Read more on action_fallback in the docs

Home

TODO: can we recreate the tag system here roughly with sections about certain subjects?

Clone this wiki locally