Routing
Phoenix router — scopes, pipelines, resources, verified routes, and helpers
The Phoenix router maps HTTP requests to controller actions or LiveView modules. It is defined in lib/my_app_web/router.ex.
Basic routing
defmodule MyAppWeb.Router do
use MyAppWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {MyAppWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", MyAppWeb do
pipe_through :browser
get "/", PageController, :index
end
endPipelines
Pipelines are stacks of plugs applied to requests. Common built-in plugs:
| Plug | Purpose |
|---|---|
:accepts |
Content negotiation |
:fetch_session |
Load session data |
:fetch_live_flash |
Merge flash for LiveView |
:put_root_layout |
Set the root layout |
:protect_from_forgery |
CSRF protection |
:put_secure_browser_headers |
Security headers (X-Frame-Options, etc.) |
:fetch_flash |
Load flash messages |
HTTP verbs
get "/posts", PostController, :index
get "/posts/new", PostController, :new
get "/posts/:id", PostController, :show
post "/posts", PostController, :create
put "/posts/:id", PostController, :update
patch "/posts/:id", PostController, :update
delete "/posts/:id", PostController, :deleteResources
resources generates all RESTful routes at once:
resources "/posts", PostController
# Generates: index, new, create, show, edit, update, delete
resources "/posts", PostController, only: [:index, :show]
resources "/posts", PostController, except: [:delete]
# Nested resources
resources "/users", UserController do
resources "/posts", PostController
end
# => /users/:user_id/posts, /users/:user_id/posts/:id, etc.Resource routes generated
| Verb | Path | Action | Helper |
|---|---|---|---|
| GET | /posts |
:index |
post_path(:index) |
| GET | /posts/new |
:new |
post_path(:new) |
| POST | /posts |
:create |
post_path(:create) |
| GET | /posts/:id |
:show |
post_path(:show, post) |
| GET | /posts/:id/edit |
:edit |
post_path(:edit, post) |
| PATCH | /posts/:id |
:update |
post_path(:update, post) |
| DELETE | /posts/:id |
:delete |
post_path(:delete, post) |
Scopes
Group routes under a URL prefix and/or module namespace:
# Module namespace is inferred from scope path
scope "/api", MyAppWeb.API do
pipe_through :api
resources "/posts", PostController # => MyAppWeb.API.PostController
end
# Custom alias
scope "/admin", as: :admin do
pipe_through :browser
resources "/users", Admin.UserController
end
# => /admin/users, admin_user_path(:index)LiveView routes
scope "/", MyAppWeb do
pipe_through :browser
# Single LiveView
live "/dashboard", DashboardLive
# LiveView with params
live "/users/:id", UserLive.Show
# LiveView with action
live "/posts", PostLive.Index
live "/posts/new", PostLive.New
live "/posts/:id/edit", PostLive.Edit
endVerified routes (sigil ~p)
Verified routes are checked at compile time against the router:
# In templates and views
~p"/posts"
~p"/posts/#{post}"
~p"/posts/#{post.id}"
# With query params
~p"/posts?page=2"
~p"/posts?#{[page: 2, sort: :title]}"Tip: Always use
~pinstead of string paths or helpers. It catches typos and renamed routes at compile time.
Inspecting routes
mix phx.routes # List all routes
mix phx.routes MyAppWeb.Router # Explicit router moduleForwarding
Delegate all requests under a path to another router or plug:
forward "/health", MyAppWeb.HealthCheckPlug
forward "/api/v1", MyAppWeb.API.V1.RouterCustom pipeline plugs
pipeline :authenticated do
plug MyAppWeb.Plugs.RequireAuth
plug :put_layout, html: {MyAppWeb.Layouts, :dashboard}
end
scope "/app", MyAppWeb do
pipe_through [:browser, :authenticated]
get "/profile", ProfileController, :show
live "/settings", SettingsLive
end