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:

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:

Source

Summary

delete(path, options, contents \\ [])

Dispatches to the path only if the request is a DELETE request. See match/3 for more examples

forward(path, options)

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

get(path, options, contents \\ [])

Dispatches to the path only if the request is a GET request. See match/3 for more examples

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 match/3 for more examples

patch(path, options, contents \\ [])

Dispatches to the path only if the request is a PATCH request. See match/3 for more examples

post(path, options, contents \\ [])

Dispatches to the path only if the request is a POST request. See match/3 for more examples

put(path, options, contents \\ [])

Dispatches to the path only if the request is a PUT request. See match/3 for more examples

Macros

delete(path, options, contents \\ [])

Dispatches to the path only if the request is a DELETE request. See match/3 for more examples.

Source
forward(path, options)

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 in match/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
Source
get(path, options, contents \\ [])

Dispatches to the path only if the request is a GET request. See match/3 for more examples.

Source
match(path, options, contents \\ [])

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 to nil, 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.
Source
options(path, options, contents \\ [])

Dispatches to the path only if the request is an OPTIONS request. See match/3 for more examples.

Source
patch(path, options, contents \\ [])

Dispatches to the path only if the request is a PATCH request. See match/3 for more examples.

Source
post(path, options, contents \\ [])

Dispatches to the path only if the request is a POST request. See match/3 for more examples.

Source
put(path, options, contents \\ [])

Dispatches to the path only if the request is a PUT request. See match/3 for more examples.

Source