{"__v":0,"_id":"5777c9635b2b430e00b982b2","category":{"version":"5777c9635b2b430e00b982a5","project":"54348ec95b10711400c6c445","_id":"5777c9635b2b430e00b982a7","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2014-10-09T04:18:04.869Z","from_sync":false,"order":1,"slug":"guides","title":"Guides"},"parentDoc":null,"project":"54348ec95b10711400c6c445","user":"5435b410495d5d0800f3a603","version":{"__v":1,"_id":"5777c9635b2b430e00b982a5","project":"54348ec95b10711400c6c445","createdAt":"2016-07-02T14:02:11.084Z","releaseDate":"2016-07-02T14:02:11.084Z","categories":["5777c9635b2b430e00b982a6","5777c9635b2b430e00b982a7","5777c9635b2b430e00b982a8","5777c9635b2b430e00b982a9","5777c9635b2b430e00b982aa"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.2.0","version":"1.2.0"},"updates":["5530029a88a30d1900851db3","5530127e0c01e717000f6614","5530c13dace7a50d00f8385d","55367fdcbabca90d007c188e","55503393a9184a1700d37225","556b12f39d4bb723007ca9fc","5571df2d8956493700aae1d7","557464f43896740d00f8829a","559e102f9e433f0d00c760b3","55a11398032ae20d0084b053","5652e18ca3de712b00d176ec","56c8dc8d8e1d9d0d0093d325","56e65cfe52d2f60e00a8003b"],"createdAt":"2015-04-14T22:01:03.677Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":7,"body":"Plug lives at the heart of Phoenix's HTTP layer, and Phoenix puts Plug front and center. We interact with plugs at every step of the connection lifecycle, and the core Phoenix components like Endpoints, Routers, and Controllers are all just Plugs internally. Let's jump in and find out just what makes Plug so special.\n\n[Plug](https://github.com/elixir-lang/plug) is a specification for composable modules in between web applications. It is also an abstraction layer for connection adapters of different web servers. The basic idea of Plug is to unify the concept of a \"connection\" that we operate on. This differs from other HTTP middleware layers such as Rack, where the request and response are separated in the middleware stack.\n\n## The Plug Specification\n\nAt the simplest level, the Plug specification comes in two flavors, *function plugs* and *module plugs*\n\n### Function Plugs\nIn order to act as a plug, a function simply needs to accept a connection struct (`%Plug.Conn{}`) and options. It also needs to return the connection struct. Any function that meets those criteria will do. Here's an example.\n\n```elixir\ndef put_headers(conn, key_values) do\n  Enum.reduce key_values, conn, fn {k, v}, conn ->\n    Plug.Conn.put_resp_header(conn, to_string(k), v)\n  end\nend\n```\n\nPretty simple, right?\n\nThis is how we use them to compose a series of transformations on our connection in Phoenix:\n\n```elixir\ndefmodule HelloPhoenix.MessageController do\n  use HelloPhoenix.Web, :controller\n\n  plug :put_headers, %{content_encoding: \"gzip\", cache_control: \"max-age=3600\"}\n  plug :put_layout, \"bare.html\"\n\n  ...\nend\n```\n\nBy abiding by the plug contract, `put_headers/2`, `put_layout/2`, and even `action/2` turn an application request into a series of explicit transformations. It doesn't stop there. To really see how effective Plug's design is, let's imagine a scenario where we need to check a series of conditions and then either redirect or halt if a condition fails. Without plug, we would end up with something like this:\n\n```elixir\ndefmodule HelloPhoenix.MessageController do\n  use HelloPhoenix.Web, :controller\n\n  def show(conn, params) do\n    case authenticate(conn) do\n      {:ok, user} ->\n        case find_message(params[\"id\"]) do\n          nil ->\n            conn |> put_flash(:info, \"That message wasn't found\") |> redirect(to: \"/\")\n          message ->\n            case authorize_message(conn, params[\"id\"]) do\n              :ok ->\n                render conn, :show, page: find_message(params[\"id\"])\n              :error ->\n                conn |> put_flash(:info, \"You can't access that page\") |> redirect(to: \"/\")\n            end\n        end\n      :error ->\n        conn |> put_flash(:info, \"You must be logged in\") |> redirect(to: \"/\")\n    end\n  end\nend\n```\n\nNotice how just a few steps of authentication and authorization require complicated nesting and duplication? Let's improve this with a couple of plugs.\n\n```elixir\ndefmodule HelloPhoenix.MessageController do\n  use HelloPhoenix.Web, :controller\n\n  plug :authenticate\n  plug :find_message\n  plug :authorize_message\n\n  def show(conn, params) do\n    render conn, :show, page: find_message(params[\"id\"])\n  end\n\n  defp authenticate(conn), do: ...\n  defp authenticate(conn, _) do\n    case Authenticator.find_user(conn) do\n      {:ok, user} ->\n        assign(conn, :user, user)\n      :error ->\n        conn |> put_flash(:info, \"You must be logged in\") |> redirect(to: \"/\") |> halt\n    end\n  end\n\n  defp find_message(id), do: ...\n  defp find_message(conn, _) do\n    case find_message(conn.params[\"id\"]) do\n      nil ->\n        conn |> put_flash(:info, \"That message wasn't found\") |> redirect(to: \"/\") |> halt\n      message ->\n        assign(conn, :message, message)\n    end\n  end\n\n  defp authorize_message(conn, _) do\n    if Authorizer.can_access?(conn.assigns[:user], conn.assigns[:message]) do\n      conn\n    else\n      conn |> put_flash(:info, \"You can't access that page\") |> redirect(to: \"/\") |> halt\n    end\n  end\nend\n```\n\nBy replacing the nested blocks of code with a flattened series of plug transformations, we are able to achieve the same functionality in a much more composable, clear, and reusable way.\n\nNow let's look at the other flavor plugs come in, module plugs.\n\n### Module Plugs\n\nModule plugs are another type of Plug that let us define a connection transformation in a module. The module only needs to implement two functions:\n\n- `init/1` which initializes any arguments or options to be passed to `call/2`\n- `call/2` which carries out the connection transformation. `call/2` is just a function plug that we saw earlier\n\n\nTo see this in action, lets write a module plug that puts the `:locale` key and value into the connection assign for downstream use in other plugs, controller actions, and our views.\n\n```elixir\ndefmodule HelloPhoenix.Plugs.Locale do\n  import Plug.Conn\n\n  :::at:::locales [\"en\", \"fr\", \"de\"]\n\n  def init(default), do: default\n\n  def call(%Plug.Conn{params: %{\"locale\" => loc}} = conn, _default) when loc in @locales do\n    assign(conn, :locale, loc)\n  end\n  def call(conn, default), do: assign(conn, :locale, default)\nend\n\ndefmodule HelloPhoenix.Router do\n  use HelloPhoenix.Web, :router\n\n  pipeline :browser do\n    plug :accepts, [\"html\"]\n    plug :fetch_session\n    plug :fetch_flash\n    plug :protect_from_forgery\n    plug :put_secure_browser_headers\n    plug HelloPhoenix.Plugs.Locale, \"en\"\n  end\n  ...\n```\n\nWe are able to add this module plug to our browser pipeline via `plug HelloPhoenix.Plugs.Locale, \"en\"`. In the `init/1` callback, we pass a default locale to use if none is present in the params. We also use pattern matching to define multiple `call/2` function heads to validate the locale in the params, and fall back to \"en\" if there is no match.\n\nThat's all there is to Plug. Phoenix embraces the plug design of composable transformations all the way up and down the stack. This is just the first taste. If we ask ourselves, \"Could I put this in a plug?\" The answer is usually, \"Yes!\"","excerpt":"","slug":"understanding-plug","type":"basic","title":"Plug"}
Plug lives at the heart of Phoenix's HTTP layer, and Phoenix puts Plug front and center. We interact with plugs at every step of the connection lifecycle, and the core Phoenix components like Endpoints, Routers, and Controllers are all just Plugs internally. Let's jump in and find out just what makes Plug so special. [Plug](https://github.com/elixir-lang/plug) is a specification for composable modules in between web applications. It is also an abstraction layer for connection adapters of different web servers. The basic idea of Plug is to unify the concept of a "connection" that we operate on. This differs from other HTTP middleware layers such as Rack, where the request and response are separated in the middleware stack. ## The Plug Specification At the simplest level, the Plug specification comes in two flavors, *function plugs* and *module plugs* ### Function Plugs In order to act as a plug, a function simply needs to accept a connection struct (`%Plug.Conn{}`) and options. It also needs to return the connection struct. Any function that meets those criteria will do. Here's an example. ```elixir def put_headers(conn, key_values) do Enum.reduce key_values, conn, fn {k, v}, conn -> Plug.Conn.put_resp_header(conn, to_string(k), v) end end ``` Pretty simple, right? This is how we use them to compose a series of transformations on our connection in Phoenix: ```elixir defmodule HelloPhoenix.MessageController do use HelloPhoenix.Web, :controller plug :put_headers, %{content_encoding: "gzip", cache_control: "max-age=3600"} plug :put_layout, "bare.html" ... end ``` By abiding by the plug contract, `put_headers/2`, `put_layout/2`, and even `action/2` turn an application request into a series of explicit transformations. It doesn't stop there. To really see how effective Plug's design is, let's imagine a scenario where we need to check a series of conditions and then either redirect or halt if a condition fails. Without plug, we would end up with something like this: ```elixir defmodule HelloPhoenix.MessageController do use HelloPhoenix.Web, :controller def show(conn, params) do case authenticate(conn) do {:ok, user} -> case find_message(params["id"]) do nil -> conn |> put_flash(:info, "That message wasn't found") |> redirect(to: "/") message -> case authorize_message(conn, params["id"]) do :ok -> render conn, :show, page: find_message(params["id"]) :error -> conn |> put_flash(:info, "You can't access that page") |> redirect(to: "/") end end :error -> conn |> put_flash(:info, "You must be logged in") |> redirect(to: "/") end end end ``` Notice how just a few steps of authentication and authorization require complicated nesting and duplication? Let's improve this with a couple of plugs. ```elixir defmodule HelloPhoenix.MessageController do use HelloPhoenix.Web, :controller plug :authenticate plug :find_message plug :authorize_message def show(conn, params) do render conn, :show, page: find_message(params["id"]) end defp authenticate(conn), do: ... defp authenticate(conn, _) do case Authenticator.find_user(conn) do {:ok, user} -> assign(conn, :user, user) :error -> conn |> put_flash(:info, "You must be logged in") |> redirect(to: "/") |> halt end end defp find_message(id), do: ... defp find_message(conn, _) do case find_message(conn.params["id"]) do nil -> conn |> put_flash(:info, "That message wasn't found") |> redirect(to: "/") |> halt message -> assign(conn, :message, message) end end defp authorize_message(conn, _) do if Authorizer.can_access?(conn.assigns[:user], conn.assigns[:message]) do conn else conn |> put_flash(:info, "You can't access that page") |> redirect(to: "/") |> halt end end end ``` By replacing the nested blocks of code with a flattened series of plug transformations, we are able to achieve the same functionality in a much more composable, clear, and reusable way. Now let's look at the other flavor plugs come in, module plugs. ### Module Plugs Module plugs are another type of Plug that let us define a connection transformation in a module. The module only needs to implement two functions: - `init/1` which initializes any arguments or options to be passed to `call/2` - `call/2` which carries out the connection transformation. `call/2` is just a function plug that we saw earlier To see this in action, lets write a module plug that puts the `:locale` key and value into the connection assign for downstream use in other plugs, controller actions, and our views. ```elixir defmodule HelloPhoenix.Plugs.Locale do import Plug.Conn @locales ["en", "fr", "de"] def init(default), do: default def call(%Plug.Conn{params: %{"locale" => loc}} = conn, _default) when loc in @locales do assign(conn, :locale, loc) end def call(conn, default), do: assign(conn, :locale, default) end defmodule HelloPhoenix.Router do use HelloPhoenix.Web, :router pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers plug HelloPhoenix.Plugs.Locale, "en" end ... ``` We are able to add this module plug to our browser pipeline via `plug HelloPhoenix.Plugs.Locale, "en"`. In the `init/1` callback, we pass a default locale to use if none is present in the params. We also use pattern matching to define multiple `call/2` function heads to validate the locale in the params, and fall back to "en" if there is no match. That's all there is to Plug. Phoenix embraces the plug design of composable transformations all the way up and down the stack. This is just the first taste. If we ask ourselves, "Could I put this in a plug?" The answer is usually, "Yes!"