I have a Router module that forwards request to other routers.
In this router I have a pipleline comprised of plug(:match)
and plug(:dispatch)
.
defmodule Example.Router do
use Plug.Router
plug(:match)
plug(:dispatch)
forward("/check", to: Example.Route.Check)
get("/", do: send_resp(conn, 200, "router"))
end
In this second module I have the same pipeline:
defmodule Example.Route.Check do
use Plug.Router
plug(:match)
plug(:dispatch)
get "/", do: send_resp(conn, 200, "ok")
end
The issue I see here is that I always seem to need plug(:match)
and plug(:dispatch)
in all Plug
Routers. So I have the following questions:
Yes, both of the plugs are always required:
The :match
plug is responsible for, well, matching the incoming request to one of the defined routes in the Router.
The :dispatch
plug is responsible for finally processing the request in the matched route.
The obvious question here would be:
Why not just do it automatically, since this needs to be done for every request?
For starters, it's because elixir has a design philosophy of doing things explicitly instead of implicitly.
Second and more importantly, plugs are executed in the order they are defined. This gives the developer full control of how incoming requests are processed.
For example, you might want to check for an Authorization
header before a route is matched and halt or continue the request from there. Or you might want to update the pageview count in a separate process, once a route is matched but before it's processed. Another common scenario is to parse a JSON request after a route is matched.
You could do all this and more by customizing the pipeline:
defmodule Example.Router do
use Plug.Router
plug(CheckRateLimit)
plug(VerifyAuthHeader)
plug(:match)
plug(LogWebRequest)
plug(Plug.Parsers, parsers: [:json], ...)
plug(:dispatch)
# ...
end
The ability to forward matched routes to other routers can make your web server much more sophisticated. For example, you could check the API rate limit in your base router, forward /admin
routes to a separate AuthorizedRouter
and put a custom VerifyAuthHeader
plug there before those routes are matched.