はじめに
前回は、Routingについてまとめてみました。
今回は、公式ドキュメントのPlugです。
なお、次回は、ガイドラインのControllerです。
消火栓
Plugは、HTTPレイヤー間のさまざまな局面で接続を行うことができる仕様です。
おおまかに関数型Plugとモジュール型Plugの二つの書き方ができます。
関数型Plug
Plugとして動作するためには、接続データ(%Plug.Conn{}
)とパラメータ引数を受け取り、接続データを返す必要があります。
例えば、以下のようなControllerを作成します(関連箇所のみ抜粋)。
defmodule HelloPhoenix.MessegeController do
use HelloPhoenix.Web, :controller
plug :put_headers, %{content_encoding: "gzip", cache_control: "max-age=3600"}
def show(conn, _params) do
render conn, "show.html"
end
defp put_headers(conn, key_values) do
# key_valuesがEnum, accumlatorがconn
# Enum.reduce/3はaccumlator(conn)を返す
Enum.reduce key_values, conn, fn {k, v}, conn ->
Plug.Conn.put_resp_header(conn, k, v)
end
end
end
これは、"show.html"を表示する前に、"content_encoding"と"cache_control"の二つのヘッダを表示します。
なお、このようにControllerに直接Pipelineを書くことができますが、記述することができるPipelineは一つだけです。
モジュール型Plug
モジュール型Plugを作成する場合、init/1とcall/2の二つの関数を実装するだけです。
init/1は、call/2へのパラメータを生成します。また、call/2は関数型Plugと同じく接続データとパラメータを引数にします。
例えば、以下のような実装を行います(関連する部分だけを抜粋)。
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
...
Pipeline :browser
に、モジュール型Plug HelloPhoenix.Plugs.Locale
を追加しています。
このとき、引数"en"が、init/1関数の引数として与えられます。
Plug(HelloPhoenix.Plugs.Locale
)が実行されるとき、HelloPhoenix.Plugs.Localeのcall
が呼び出されます。