Router
We have used Phoenix.Router plenty of times in Phoenix Basics, and you probably already understand the basics. So this is just a small chapter with some useful extra details.
| Phoenix 1.8 includes verified routes with the ~psigil that provides compile-time verification of routes. Instead of using the traditional helpers likeRoutes.user_path(conn, :show, user), you can now use~p"/users/#{user}"which is simpler and provides compile-time safety. Phoenix 1.8 also introduces scopes for secure data access and authorization. | 
All code in this chapter will result from this base application:
$ mix phx.new demo --no-ecto --no-dashboard (1)
$ cd demo| 1 | We don’t include the Phoenix.LiveDashboard (--no-dashboard) to keep our router setup tidy. Otherwise, there will be many routes created just for the real-time performance monitoring dashboard, which is not a topic in this chapter. | 
This results in a minimal router setup:
defmodule DemoWeb.Router do
  use DemoWeb, :router
  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end
  pipeline :api do
    plug :accepts, ["json"]
  end
  scope "/", DemoWeb do
    pipe_through :browser
    get "/", PageController, :index
  end
endAt this stage, we will concentrate on the last function, which starts with scope "/".
Display existing routes
Running the command mix phx.routes will return a list of all defined routes. In our vanilla demo system, this is the output:
$ mix phx.routes
Compiling 13 files (.ex)
Generated demo app
page_path  GET  /                    DemoWeb.PageController :index (1)
websocket  WS   /socket/websocket    DemoWeb.UserSocket (2)| 1 | This route is for a HTTP GET request for the root path - which gets matched by /- of our application. It triggers the:indexaction in theDemoWeb.PageControllercontroller. | 
| 2 | No need to discuss websocketsin this chapter. I will remove that line in following examples to clean up the output. | 
| In more complex applications with a dashboard, the output of mix phx.routesgets quite a bit longer. Thenmix phx.routes | grep "search-item"is a useful way of filtering the output. | 
Params
There are many times when you will want to set a parameter, such as ID, in the route. The following example will look at how we can set the parameter in the router, and how we can access it in the controller.
[...]
scope "/", DemoWeb do
  pipe_through :browser
  get "/", PageController, :index
  get "/products/:id", ProductController, :show (1)
end
[...]| 1 | We ask the router to match everything at that position to the parameter :id. | 
defmodule DemoWeb.ProductController do
  use DemoWeb, :controller
  def show(conn, %{"id" => id}) do (1)
    conn
    |> assign(:id, id) (2)
    |> render("show.html")
  end
end| 1 | We match the idin the params. | 
| 2 | In this example, we just add the id to the assignsmap. Normally, we would have fetched the product with that ID from the database and manipulated the data before rendering the template. | 
defmodule DemoWeb.ProductView do
  use DemoWeb, :view
end<h1>ID: <%= @id %></h1> (1)| 1 | Just a simple display. | 
If you open http://localhost:4000/products/1 in your browser, you’ll see this log entry in the terminal:
[info] GET /products/1
[debug] Processing with DemoWeb.ProductController.show/2
  Parameters: %{"id" => "1"}
  Pipelines: [:browser]
[info] Sent 200 in 373µsAnd here is the screenshot:

Query String
To handle query strings, we do not need to add anything to the router. We just need to make some small changes to the controller.
For example, if we add the query string "color=blue" to our product request (http://localhost:4000/products/1?color=blue) and open this URL in the browser, we can see from the log entry (shown below) that Phoenix has automatically added color to the params (parameters) map.
[info] GET /products/1
[debug] Processing with DemoWeb.ProductController.show/2
  Parameters: %{"color" => "blue", "id" => "1"} (1)
  Pipelines: [:browser]
[info] Sent 200 in 600µs| 1 | Both parameters have been added to the paramsmap. | 
Without adding anything to the router, the query string parameter color can be accessed in the controller, but we need to make a few changes to the controller:
defmodule DemoWeb.ProductController do
  use DemoWeb, :controller
  def show(conn, %{"id" => id, "color" => color}) do (1)
    conn
    |> assign(:id, id)
    |> assign(:color, color) (2)
    |> render("show.html")
  end
  def show(conn, %{"id" => id}) do (3)
    conn
    |> assign(:id, id)
    |> render("show.html")
  end
end| 1 | This show/2function matches if there is an:idand a:colorparameter. | 
| 2 | In addition to :idwe have to assign:colortoo. | 
| 3 | This show/2function matches if there is only an:idparameter. | 
| The order of the show/2functions in the controller is significant. If we use the other order for this specific example the%{"id" ⇒ id, "color" ⇒ color}would never match because%{"id" ⇒ id}always matches first if it’s the first function. | 
Lastly we have to change the template:
<h1>ID: <%= @id %></h1>
<%= if assigns[:color] do %> (1)
<p>Color: <%= @color %></p>
<% end %>| 1 | Because we call this template from two different functions we have to take care of the case when the color assigns hasn’t taken place. Alternatively, we could use a different template for each function. | 

A view of the routes:
$ mix phx.routes
Compiling 1 file (.ex)
   page_path  GET  /                                      DemoWeb.PageController :index
product_path  GET  /products/:id                          DemoWeb.ProductController :showLink with params
Assuming you’d like to link to the next product ID this would be the template:
<h1>ID: <%= @id %></h1>
<%= if assigns[:color] do %> (1)
<p>Color: <%= @color %></p>
<% end %>
<%= link "Next", to: Routes.product_path(@conn, :show, String.to_integer(@id) + 1) %> (1)| 1 | We use the DemoWeb.ProductController :showroute and add theidto it. To increase the current@idwe have to callString.to_integer/1first. | 
Link with query
And if you would like to link to the first product with the query "color=orange", you would use this code:
<h1>ID: <%= @id %></h1>
<%= if assigns[:color] do %> (1)
<p>Color: <%= @color %></p>
<% end %>
<%= link "First product in orange", to: Routes.product_path(@conn, :show, 1, color: "orange") %> (1)| 1 | This returns a link to http://localhost:4000/products/1?color=orange | 
Multilevel Paths
In the previous easy code examples, we always put the routes on the first level. But of course, you can use paths with sublevels too. Here’s an example:
[...]
scope "/", DemoWeb do
  pipe_through :browser
  get "/an-other-test/abc/def/", PageController, :index
end
[...]No surprise here:
$ mix phx.routes
Compiling 1 file (.ex)
page_path  GET  /an-other-test/abc/def    DemoWeb.PageController :indexWildcards
You don’t have to define the route precisely. You can use the * wildcard too.
[...]
scope "/", DemoWeb do
  pipe_through :browser
  get "/names/st*an", PageController, :index
end
[...]This route matches /names/stefan and /names/stephan:
[info] GET /names/stefan
[debug] Processing with DemoWeb.PageController.index/2
  Parameters: %{"an" => ["stefan"]} (1)
  Pipelines: [:browser]
[info] Sent 200 in 4ms
[info] GET /names/stephan
[debug] Processing with DemoWeb.PageController.index/2
  Parameters: %{"an" => ["stephan"]}
  Pipelines: [:browser]
[info] Sent 200 in 1ms| 1 | The parameter is automatically named an, and it contains the whole match. You can use that to do some interesting things. | 
Misc
There’s no need to replicate the official documentation in this chapter. By now, you understand the concept of Phoenix.Router. You’ll find solutions for all the exceptional cases which are not handled in this chapter in the official documentation at https://hexdocs.pm/phoenix/Phoenix.Router.html