Plug.Router
A DSL to define a routing algorithm that works with Plug.
It provides a set of macros to generate routes. For example:
defmodule AppRouter do
use Plug.Router
plug :match
plug :dispatch
get "/hello" do
send_resp(conn, 200, "world")
end
match _ do
send_resp(conn, 404, "oops")
end
end
Each route needs to return a connection, as per the Plug spec.
A catch-all match
is recommended to be defined as in the example
above, otherwise routing fails with a function clause error.
The router is itself a plug, which means it can be invoked as:
AppRouter.call(conn, AppRouter.init([]))
Notice the router contains a plug pipeline and by default it requires
two plugs: match
and dispatch
. match
is responsible for
finding a matching route which is then forwarded to dispatch
.
This means users can easily hook into the router mechanism and add
behaviour before match, before dispatch or after both.
Routes
get "/hello" do
send_resp(conn, 200, "world")
end
In the example above, a request will only match if it is a GET
request and
the route is “/hello”. The supported HTTP methods are get
, post
, put
,
patch
, delete
and options
.
A route can also specify parameters which will then be available in the function body:
get "/hello/:name" do
send_resp(conn, 200, "hello #{name}")
end
Routes allow for globbing which will match the remaining parts of a route and can be available as a parameter in the function body. Also note that a glob can’t be followed by other segments:
get "/hello/*_rest" do
send_resp(conn, 200, "matches all routes starting with /hello")
end
get "/hello/*glob" do
send_resp(conn, 200, "route after /hello: #{inspect glob}")
end
Finally, a general match
function is also supported:
match "/hello" do
send_resp(conn, 200, "world")
end
A match
will match any route regardless of the HTTP method.
Check match/3
for more information on how route compilation
works and a list of supported options.
Error handling
In case something goes wrong in a request, the router by default will crash, without returning any response to the client. This behaviour can be configured in two ways, by using two different modules:
Plug.ErrorHandler
- allows the developer to customize exactly which page is sent to the client via thehandle_errors/2
function;Plug.Debugger
- automatically shows debugging and request information about the failure. This module is recommended to be used only in a development environment.
Here is an example of how both modules could be used in an application:
defmodule AppRouter do
use Plug.Router
if Mix.env == :dev do
use Plug.Debugger
end
use Plug.ErrorHandler
plug :match
plug :dispatch
get "/hello" do
send_resp(conn, 200, "world")
end
defp handle_errors(conn, %{kind: _kind, reason: _reason, stack: _stack}) do
send_resp(conn, conn.status, "Something went wrong")
end
end
Routes compilation
All routes are compiled to a match function that receives
three arguments: the method, the request path split on /
and the connection. Consider this example:
match "/foo/bar", via: :get do
send_resp(conn, 200, "hello world")
end
It is compiled to:
defp match("GET", ["foo", "bar"], conn) do
send_resp(conn, 200, "hello world")
end
This opens up a few possibilities. First, guards can be given
to match
:
match "/foo/:bar" when size(bar) <= 3, via: :get do
send_resp(conn, 200, "hello world")
end
Second, a list of split paths (which is the compiled result) is also allowed:
match ["foo", bar], via: :get do
send_resp(conn, 200, "hello world")
end
After a match is found, the block given as do/end
is stored
as a function in the connection. This function is then retrieved
and invoked in the dispatch
plug.
Options
When used, the following options are accepted by Plug.Router
:
:log_on_halt
- accepts the level to log whenever the request is halted
Summary↑
delete(path, options, contents \\ []) | Dispatches to the path only if the request is a DELETE request.
See |
forward(path, options) | Forwards requests to another Plug. The |
get(path, options, contents \\ []) | Dispatches to the path only if the request is a GET request.
See |
match(path, options, contents \\ []) | Main API to define routes |
options(path, options, contents \\ []) | Dispatches to the path only if the request is an OPTIONS request.
See |
patch(path, options, contents \\ []) | Dispatches to the path only if the request is a PATCH request.
See |
post(path, options, contents \\ []) | Dispatches to the path only if the request is a POST request.
See |
put(path, options, contents \\ []) | Dispatches to the path only if the request is a PUT request.
See |
Macros
Dispatches to the path only if the request is a DELETE request.
See match/3
for more examples.
Forwards requests to another Plug. The path_info
of the forwarded
connection will exclude the portion of the path specified in the
call to forward
.
Options
forward
accepts the following options:
:to
- a Plug where the requests will be forwarded to.:host
- a string representing the host or subdomain, exactly like inmatch/3
.
All remaining options are passed to the target plug.
Examples
forward "/users", to: UserRouter
Assuming the above code, a request to /users/sign_in
will be forwarded to
the UserRouter
plug, which will receive what it will see as a request to
/sign_in
.
Some other examples:
forward "/foo/bar", to: :foo_bar_plug, host: "foobar."
forward "/api", to: ApiRouter, plug_specific_option: true
Dispatches to the path only if the request is a GET request.
See match/3
for more examples.
Main API to define routes.
It accepts an expression representing the path and many options allowing the match to be configured.
Examples
match "/foo/bar", via: :get do
send_resp(conn, 200, "hello world")
end
Options
match/3
and the others route macros accept the following options:
:host
- the host which the route should match. Defaults tonil
, meaning no host match, but can be a string like “example.com” or a string ending with “.”, like “subdomain.” for a subdomain match.:via
- matches the route against some specific HTTP method (specified as an atom, like:get
or:put
.:do
- contains the implementation to be invoked in case the route matches.
Dispatches to the path only if the request is an OPTIONS request.
See match/3
for more examples.
Dispatches to the path only if the request is a PATCH request.
See match/3
for more examples.
Dispatches to the path only if the request is a POST request.
See match/3
for more examples.
Dispatches to the path only if the request is a PUT request.
See match/3
for more examples.