Skip to content

Commit

Permalink
Add route_info lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismccord committed May 17, 2019
1 parent b210c62 commit d7d1b63
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 4 deletions.
37 changes: 35 additions & 2 deletions lib/phoenix/router.ex
Expand Up @@ -266,7 +266,7 @@ defmodule Phoenix.Router do
def __call__(%{private: %{phoenix_bypass: :all}} = conn, _match) do
conn
end
def __call__(conn, {path_params, prepare, pipeline, {plug, opts}}) do
def __call__(conn, {_route, path_params, prepare, pipeline, {plug, opts}}) do
case conn |> prepare.(path_params) |> pipeline.() do
%Plug.Conn{halted: true} = halted_conn ->
halted_conn
Expand Down Expand Up @@ -389,7 +389,8 @@ defmodule Phoenix.Router do

@doc false
def __match_route__(unquote(verb_match), unquote(path), unquote(host)) do
{unquote(path_params),
{unquote(Macro.escape(route)),
unquote(path_params),
fn var!(conn, :conn), var!(path_params, :conn) -> unquote(prepare) end,
&unquote(Macro.var(pipe_name, __MODULE__))/1,
unquote(dispatch)}
Expand Down Expand Up @@ -811,4 +812,36 @@ defmodule Phoenix.Router do
unquote(add_route(:forward, :*, path, plug, plug_opts, router_opts))
end
end

@doc """
Returns the compile-time route info and runtime path params for a request.
A tuple is returned containing matching `%Phoenix.Router.Route{}` struct and
the path params that matched the request path.
## Examples
iex> Phoenix.Router.route_info(MyRouter, "GET", "/posts/123", "myhost")
{%Phoenix.Router.Route{
assigns: %{},
helper: "post",
host: nil,
kind: :match,
opts: :show,
path: "/posts/:id",
pipe_through: [:browser],
plug: MyAppWeb.PostController,
verb: :get
}, %{"id" => "123"}}
iex> Phoenix.Router.route_info(MyRouter, "GET", "/not-exists", "myhost")
:error
"""
def route_info(router, method, path, host) do
split_path = for segment <- String.split(path, "/"), segment != "", do: segment
case router.__match_route__(method, split_path, host) do
{%Route{} = route, path_params, _prepare, _pipes, _dispatch} -> {route, path_params}
:error -> :error
end
end
end
2 changes: 1 addition & 1 deletion lib/phoenix/test/conn_test.ex
Expand Up @@ -580,7 +580,7 @@ defmodule Phoenix.ConnTest do
case router.__match_route__("GET", path_info, host || conn.host) do
:error ->
raise Phoenix.Router.NoRouteError, conn: conn, router: router
{path_params, _prepare, _pipes, _dispatch} ->
{_route, path_params, _prepare, _pipes, _dispatch} ->
Enum.into(path_params, %{}, fn {key, val} -> {String.to_atom(key), val} end)
end
end
Expand Down
50 changes: 49 additions & 1 deletion test/phoenix/router/routing_test.exs
Expand Up @@ -29,7 +29,7 @@ defmodule Phoenix.Router.RoutingTest do
get "/backups/*path", UserController, :image
get "/static/images/icons/*image", UserController, :image

trace "/trace", UserController, :trace
trace("/trace", UserController, :trace)
options "/options", UserController, :options
connect "/connect", UserController, :connect
match :move, "/move", UserController, :move
Expand Down Expand Up @@ -165,4 +165,52 @@ defmodule Phoenix.Router.RoutingTest do
assert conn.status == 200
assert conn.resp_body == "users any"
end

test "route_info returns route string and path params" do
assert {%Phoenix.Router.Route{
assigns: %{},
helper: "user",
host: nil,
kind: :match,
line: 39,
opts: :not_found,
path: "/*path",
pipe_through: [],
plug: Phoenix.Router.RoutingTest.UserController,
private: %{},
verb: :get
},
%{"path" => ["foo", "bar", "baz"]}} =
Phoenix.Router.route_info(Router, "GET", "foo/bar/baz", nil)

assert {%Phoenix.Router.Route{
assigns: %{},
helper: "users",
host: nil,
kind: :match,
line: 24,
opts: :show,
path: "/users/:id",
pipe_through: [],
plug: Phoenix.Router.RoutingTest.UserController,
private: %{},
verb: :get
}, %{"id" => "1"}} = Phoenix.Router.route_info(Router, "GET", "users/1", nil)

assert {%Phoenix.Router.Route{
assigns: %{},
helper: "users",
host: nil,
kind: :match,
line: 22,
opts: :index,
path: "/",
pipe_through: [],
plug: Phoenix.Router.RoutingTest.UserController,
private: %{},
verb: :get
}, %{}} = Phoenix.Router.route_info(Router, "GET", "/", "host")

assert Phoenix.Router.route_info(Router, "POST", "/not-exists", "host") == :error
end
end

0 comments on commit d7d1b63

Please sign in to comment.