Conveniences for building plugs.
This module can be use
-d into a module in order to build a plug pipeline:
defmodule MyApp do use Plug.Builder plug Plug.Logger plug :hello, upper: true # A function from another module can be plugged too, provided it's # imported into the current module first. import AnotherModule, only: [interesting_plug: 2] plug :interesting_plug def hello(conn, opts) do body = if opts[:upper], do: "WORLD", else: "world" send_resp(conn, 200, body) end end
Multiple plugs can be defined with the plug/2
macro, forming a pipeline. The plugs in the pipeline will be executed in the order they've been added through the plug/2
macro. In the example above, Plug.Logger
will be called first and then the :hello
function plug will be called on the resulting connection.
Plug.Builder
also imports the Plug.Conn
module, making functions like send_resp/3
available.
When used, the following options are accepted by Plug.Builder
:
:log_on_halt
- accepts the level to log whenever the request is halted:init_mode
- the environment to initialize the plug's options, one of :compile
or :runtime
. Defaults :compile
.Internally, Plug.Builder
implements the Plug
behaviour, which means both the init/1
and call/2
functions are defined.
By implementing the Plug API, Plug.Builder
guarantees this module is a plug and can be handed to a web server or used as part of another pipeline.
Both the init/1
and call/2
functions defined by Plug.Builder
can be manually overridden. For example, the init/1
function provided by Plug.Builder
returns the options that it receives as an argument, but its behaviour can be customized:
defmodule PlugWithCustomOptions do use Plug.Builder plug Plug.Logger def init(opts) do opts end end
The call/2
function that Plug.Builder
provides is used internally to execute all the plugs listed using the plug
macro, so overriding the call/2
function generally implies using super
in order to still call the plug chain:
defmodule PlugWithCustomCall do use Plug.Builder plug Plug.Logger plug Plug.Head def call(conn, opts) do conn |> super(opts) # calls Plug.Logger and Plug.Head |> assign(:called_all_plugs, true) end end
A plug pipeline can be halted with Plug.Conn.halt/1
. The builder will prevent further plugs downstream from being invoked and return the current connection. In the following example, the Plug.Logger
plug never gets called:
defmodule PlugUsingHalt do use Plug.Builder plug :stopper plug Plug.Logger def stopper(conn, _opts) do halt(conn) end end
Annotates a plug will receive the options given to the current module itself as arguments.
Compiles a plug pipeline.
A macro that stores a new plug. opts
will be passed unchanged to the new plug.
plug() :: module() | atom()
Annotates a plug will receive the options given to the current module itself as arguments.
Imagine the following plug:
defmodule MyPlug do use Plug.Builder plug :inspect_opts, builder_opts() defp inspect_opts(conn, opts) do IO.inspect(opts) conn end end
When plugged as:
plug MyPlug, custom: :options
It will print [custom: :options]
as the builder options were passed to the inner plug.
Note you only pass builder_opts()
to function plugs. You cannot use builder_opts()
with module plugs because their options are evaluated at compile time. If you need to pass builder_opts()
to a module plug, you can wrap the module plug in function. To be precise, do not do this:
plug Plug.Parsers, builder_opts()
Instead do this:
plug :custom_plug_parsers, builder_opts() defp custom_plug_parsers(conn, opts) do Plug.Parsers.call(conn, Plug.Parsers.init(opts)) end
compile(Macro.Env.t(), [{plug(), Plug.opts(), Macro.t()}], Keyword.t()) :: {Macro.t(), Macro.t()}
Compiles a plug pipeline.
Each element of the plug pipeline (according to the type signature of this function) has the form:
{plug_name, options, guards}
Note that this function expects a reversed pipeline (with the last plug that has to be called coming first in the pipeline).
The function returns a tuple with the first element being a quoted reference to the connection and the second element being the compiled quoted pipeline.
Plug.Builder.compile(env, [ {Plug.Logger, [], true}, # no guards, as added by the Plug.Builder.plug/2 macro {Plug.Head, [], quote(do: a when is_binary(a))} ], [])
A macro that stores a new plug. opts
will be passed unchanged to the new plug.
This macro doesn't add any guards when adding the new plug to the pipeline; for more information about adding plugs with guards see compile/3
.
plug Plug.Logger # plug module plug :foo, some_options: true # plug function
© 2013 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/plug/Plug.Builder.html