Is this the only way to give a verified route as an argument to a plug?

Hello there,

The only way I found to provide a verified route as options to a plug is the following syntax:

plug AppWeb.Plugs.ManageBackPath, default_path_fn: &AppWeb.RoomController.room_path/0

def room_path, do: ~p"/rooms"

I tried an anonymous function

plug AppWeb.Plugs.ManageBackPath, default_path_fn: fn -> ~p"/rooms" end

I get

== Compilation error in file lib/app_web/controllers/room/room_controller.ex ==
** (ArgumentError) cannot escape #Function<0.100776851/1 in :elixir_compiler_203.__MODULE__/1>. The supported values are: lists, tuples, maps, atoms, numbers, bitstrings, PIDs and remote functions in the format &Mod.fun/arity

And of course

plug AppWeb.Plugs.ManageBackPath, default_path_fn: ~p"/rooms"

Gives

== Compilation error in file lib/app_web/controllers/room/room_controller.ex ==
** (RuntimeError) Phoenix.VerifiedRoutes can only be used inside functions, please move your usage of ~p to functions

Having to define a full function for each param seems to be the only accepted syntax, but having a public function in my controller looks wrong too.

It’s probably possible to hide that in a macro… but not convinced this is the best path to take.

1 Like

One other option is to use a plain route option and in your plug’s init/1 use route_info/4 to validate. Just raise on :error and it will produce a compile-time error.

1 Like

Won’t that produce a runtime only error though?

It could work for our use case however, a runtime error at the plug level means we’d catch it pretty early if we were to change the route.

def init(default_path: default_path) do
  case Phoenix.Router.route_info(AppWeb.Router, "GET", default_path, nil) do
    :error -> raise ArgumentError, "Invalid default_path: #{default_path}"
    _ -> default_path
  end
end

that’s what I got

Try compiling with prod Mix environment. It should raise the error.

1 Like

Wow! I wasn’t aware of this at all :sweat_smile: Can you point me to some documentation? I’m trying right now with :test env because I’d want it to fail the CI before the prod build too.

EDIT: doesn’t say anyhting in test, i’ll see if we can / want to change that.
EDIT2: yep, we got that in config_test.exs, i’m going to bench

# Initialize plugs at runtime for faster test compilation
config :phoenix, :plug_init_mode, :runtime

EDIT3: 1mn30 to 1mn45, not worth the loss, it’s goind to fail anway on relase. Thanks a lot!

1 Like

Plugs init/1 callback is executed at compile time by default, which can be changed by configuring plugs :init_mode to :runtime. The latter is set by phoenix for :dev to keep compile times quicker.

2 Likes