View Source Phoenix.VerifiedRoutes (Phoenix v1.7.19)
Provides route generation with compile-time verification.
Use of the sigil_p
macro allows paths and URLs throughout your
application to be compile-time verified against your Phoenix router(s).
For example, the following path and URL usages:
<.link href={~p"/sessions/new"} method="post">Log in</.link>
redirect(to: url(~p"/posts/#{post}"))
Will be verified against your standard Phoenix.Router
definitions:
get "/posts/:post_id", PostController, :show
post "/sessions/new", SessionController, :create
Unmatched routes will issue compiler warnings:
warning: no route path for AppWeb.Router matches "/postz/#{post}"
lib/app_web/controllers/post_controller.ex:100: AppWeb.PostController.show/2
Additionally, interpolated ~p values are encoded via the Phoenix.Param
protocol.
For example, a %Post{}
struct in your application may derive the Phoenix.Param
protocol to generate slug-based paths rather than ID based ones. This allows you to
use ~p"/posts/#{post}"
rather than ~p"/posts/#{post.slug}"
throughout your
application. See the Phoenix.Param
documentation for more details.
Finally, query strings are also supported in verified routes, either in traditional form:
~p"/posts?page=#{page}"
Or as a keyword list or map of values:
params = %{page: 1, direction: "asc"}
~p"/posts?#{params}"
Like path segments, query strings params are proper URL encoded and may be interpolated directly into the ~p string.
What about named routes?
Many web frameworks, and early versions of Phoenix, provided a feature called "named routes". The idea is that, when you define routes in your web applications, you could give them names too. In Phoenix that was done as follows:
get "/login", SessionController, :create, as: :login
And now you could generate the route usnig the login_path
function.
Named routes exist to avoid hardcoding routes in your templates, if you wrote <a href="/login">
and then changed your router, the link would point to a page that no longer exist. By using
login_path
, we make sure it always points to a valid URL in our router. However, named routes
come with the downsides of indirection: when you look at the code, it is not immediately clear
which URL will be generated. Furthermore, if you have an existing URL and you want to add it
to a template, you need to do a reverse lookup and find its name in the router. At the end of
the day, named routes are arbitrary names that need to be memorized by developers, adding
cognitive overhead.
Verified routes tackle this problem by allowing the routes to be written as we would read them
in a browser, but using the ~p
sigil to guarantee they actually exist at compilation time.
They remove the indirection of named routes while keeping their guarantees.
In any case, if part of your application requires features similar to named routes, then remember you can still leverage Elixir features to achieve the same result. For example, you can define several functions as named routes to be reused across modules:
def login_path, do: ~p"/login"
def user_home_path(user), do: ~p"/users/#{user.username}"
Options
To verify routes in your application modules, such as controller, templates, and views,
use Phoenix.VerifiedRoutes
, which supports the following options:
:router
- The required router to verify ~p paths against:endpoint
- The optional endpoint for ~p script_name and URL generation:statics
- The optional list of static directories to treat as verified paths
For example:
use Phoenix.VerifiedRoutes,
router: AppWeb.Router,
endpoint: AppWeb.Endpoint,
statics: ~w(images)
Usage
The majority of path and URL generation needs your application will be met
with ~p
and url/1
, where all information necessary to construct the path
or URL is provided by the compile-time information stored in the Endpoint
and Router passed to use Phoenix.VerifiedRoutes
.
That said, there are some circumstances where path/2
, path/3
, url/2
, and url/3
are required:
When the runtime values of the
%Plug.Conn{}
,%Phoenix.LiveSocket{}
, or a%URI{}
dictate the formation of the path or URL, which happens under the following scenarios:Phoenix.Controller.put_router_url/2
is used to override the endpoint's URLPhoenix.Controller.put_static_url/2
is used to override the endpoint's static URL
When the Router module differs from the one passed to
use Phoenix.VerifiedRoutes
, such as library code, or application code that relies on multiple routers. In such cases, the router module can be provided explicitly topath/3
andurl/3
.
Tracking Warnings
All static path segments must start with forward slash, and you must have a static segment between dynamic interpolations in order for a route to be verified without warnings. For example, the following path generates proper warnings
~p"/media/posts/#{post}"
While this one will not allow the compiler to see the full path:
type = "posts"
~p"/media/#{type}/#{post}"
In such cases, it's better to write a function such as media_path/1
which branches
on different ~p
's to handle each type.
Like any other compilation warning, the Elixir compiler will warn any time the file
that a ~p resides in changes, or if the router is changed. To view previously issued
warnings for files that lack new changes, the --all-warnings
flag may be passed to
the mix compile
task. For the following will show all warnings the compiler
has previously encountered when compiling the current application code:
$ mix compile --all-warnings
*Note: Elixir >= 1.14.0 is required for comprehensive warnings. Older versions will compile properly, but no warnings will be issued.
Summary
Functions
Generates the router path with route verification.
Generates the router path with route verification.
Generates the router path with route verification.
Generates an integrity hash to a static asset given its file path.
Generates path to a static asset given its file path.
Generates url to a static asset given its file path.
Returns the path with relevant script name prefixes without verification.
Returns the URL for the endpoint from the path without verification.
Generates the router url with route verification.
Generates the router url with route verification from the connection, socket, or URI.
Generates the url with route verification from the connection, socket, or URI and router.
Functions
Generates the router path with route verification.
See sigil_p/2
for more information.
Warns when the provided path does not match against the router specified
in use Phoenix.VerifiedRoutes
or the @router
module attribute.
Examples
import Phoenix.VerifiedRoutes
redirect(to: path(conn, ~p"/users/top"))
redirect(to: path(conn, ~p"/users/#{@user}"))
~H"""
<.link href={path(@uri, "/users?page=#{@page}")}>profile</.link>
<.link href={path(@uri, "/users?#{@params}")}>profile</.link>
"""
Generates the router path with route verification.
See sigil_p/2
for more information.
Warns when the provided path does not match against the router specified in the router argument.
Examples
import Phoenix.VerifiedRoutes
redirect(to: path(conn, MyAppWeb.Router, ~p"/users/top"))
redirect(to: path(conn, MyAppWeb.Router, ~p"/users/#{@user}"))
~H"""
<.link href={path(@uri, MyAppWeb.Router, "/users?page=#{@page}")}>profile</.link>
<.link href={path(@uri, MyAppWeb.Router, "/users?#{@params}")}>profile</.link>
"""
Generates the router path with route verification.
Interpolated named parameters are encoded via the Phoenix.Param
protocol.
Warns when the provided path does not match against the router specified
in use Phoenix.VerifiedRoutes
or the @router
module attribute.
Examples
use Phoenix.VerifiedRoutes, endpoint: MyAppWeb.Endpoint, router: MyAppWeb.Router
redirect(to: ~p"/users/top")
redirect(to: ~p"/users/#{@user}")
~H"""
<.link href={~p"/users?page=#{@page}"}>profile</.link>
<.link href={~p"/users?#{@params}"}>profile</.link>
"""
Generates an integrity hash to a static asset given its file path.
See Phoenix.Endpoint.static_integrity/1
for more information.
Examples
iex> static_integrity(conn, "/assets/app.js")
"813dfe33b5c7f8388bccaaa38eec8382"
iex> static_integrity(socket, "/assets/app.js")
"813dfe33b5c7f8388bccaaa38eec8382"
iex> static_integrity(AppWeb.Endpoint, "/assets/app.js")
"813dfe33b5c7f8388bccaaa38eec8382"
Generates path to a static asset given its file path.
See Phoenix.Endpoint.static_path/1
for more information.
Examples
iex> static_path(conn, "/assets/app.js")
"/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js"
iex> static_path(socket, "/assets/app.js")
"/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js"
iex> static_path(AppWeb.Endpoint, "/assets/app.js")
"/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js"
iex> static_path(%URI{path: "/subresource"}, "/assets/app.js")
"/subresource/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js"
Generates url to a static asset given its file path.
See Phoenix.Endpoint.static_url/0
and Phoenix.Endpoint.static_path/1
for more information.
Examples
iex> static_url(conn, "/assets/app.js")
"https://example.com/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js"
iex> static_url(socket, "/assets/app.js")
"https://example.com/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js"
iex> static_url(AppWeb.Endpoint, "/assets/app.js")
"https://example.com/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js"
Returns the path with relevant script name prefixes without verification.
Examples
iex> unverified_path(conn, AppWeb.Router, "/posts")
"/posts"
iex> unverified_path(conn, AppWeb.Router, "/posts", page: 1)
"/posts?page=1"
Returns the URL for the endpoint from the path without verification.
Examples
iex> unverified_url(conn, "/posts")
"https://example.com/posts"
iex> unverified_url(conn, "/posts", page: 1)
"https://example.com/posts?page=1"
Generates the router url with route verification.
See sigil_p/2
for more information.
Warns when the provided path does not match against the router specified
in use Phoenix.VerifiedRoutes
or the @router
module attribute.
Examples
use Phoenix.VerifiedRoutes, endpoint: MyAppWeb.Endpoint, router: MyAppWeb.Router
redirect(to: url(conn, ~p"/users/top"))
redirect(to: url(conn, ~p"/users/#{@user}"))
~H"""
<.link href={url(@uri, "/users?#{[page: @page]}")}>profile</.link>
"""
The router may also be provided in cases where you want to verify routes for a
router other than the one passed to use Phoenix.VerifiedRoutes
:
redirect(to: url(conn, OtherRouter, ~p"/users"))
Forwarded routes are also resolved automatically. For example, imagine you have a forward path to an admin router in your main router:
defmodule AppWeb.Router do
...
forward "/admin", AppWeb.AdminRouter
end
defmodule AppWeb.AdminRouter do
...
get "/users", AppWeb.Admin.UserController
end
Forwarded paths in your main application router will be verified as usual,
such as ~p"/admin/users"
.
Generates the router url with route verification from the connection, socket, or URI.
See url/1
for more information.
Generates the url with route verification from the connection, socket, or URI and router.
See url/1
for more information.