Plug v1.7.1 Plug.Builder

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.

Options

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.

Plug behaviour

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.

Overriding the default Plug API functions

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

Halting a plug pipeline

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

Summary

Types

Functions

builder_opts()

Annotates a plug will receive the options given to the current module itself as arguments

compile(env, pipeline, builder_opts)

Compiles a plug pipeline

plug(plug, opts \\ [])

A macro that stores a new plug. opts will be passed unchanged to the new plug

Types

Link to this type plug()
plug() :: module() | atom()

Functions

Link to this macro builder_opts() (macro)

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
Link to this function compile(env, pipeline, builder_opts)
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.

Examples

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))}
], [])
Link to this macro plug(plug, opts \\ []) (macro)

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/1.

Examples

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/1.7.1/Plug.Builder.html