257 words, 2 min read

I must say that I quite like the idea of centralizing the verified routes in your Phoenix app in a separate module as suggested here:

A relatively new feature of Phoenix is verified routes, which lets you create routes with the ~p sigil that result in compiler warnings when the route is invalid. For example, ~p"/users/new" will fail if there is no such path defined.

You can sprinkle your code with ~p sigils, but I’ve found that there are advantages to having a module that contains functions for each path in your project, like this:

web/paths.ex

defmodule Web.Paths do
use Web, :verified_routes
@customer_id "58-gkjScjj8"
def home, do: ~p"/"
def invitation(%Schema.User{type: admin} = user), do: ~p"/admin/invitation/#{user.id}"
def invitation(user), do: ~p"/invitation/#{user.id}"
def login, do: ~p"/auth/login"
def logo, do: static("images/logo.png")
def remote_auth, do: "https://auth29-g.example.net/customer/#{@customer_id}/auth"
def styleguide(module, function), do: ~p"/styleguide/#{module}/#{function}"
end

Note that in this example, the module is Web.Paths, not MyAppWeb.Paths. See Phoenix Project Layout for more info.

More things to note:

  • As a plain module with functions, your editor can autocomplete your routes.
  • The functions usually fit on a single line, so you can see a lot more routes at a time.
  • A different invitation path is returned by pattern matching on the user type which reduces the need for duplicated code that chooses the correct route.
  • The logo isn’t a ~p sigil but using the generated route works the same as other routes.
  • Function parameters are listed so it’s easy to tell what’s required.
  • You can name your functions something that’s more meaningful than the path or URL.