Elixirのplugがさっぱり理解できない

Elixirのplugという仕組みがさっぱり理解できないので、記事を書きながら理解を進めていくメモ

 

 

plug概要

plugのリポジトリはこちら。

GitHub - elixir-plug/plug: A specification and conveniences for composable modules between web applications

 

自分なりにソースコードを見てみて理解したのは以下のような感じ。(違ってても責任はとれません)

 

  • ElixirでWebアプリケーションを作るための仕組みである。
  • webアプリケーションを構築するための情報を集約したconnという構造体をするのがPlugライブラリである。
  • 関数plugとモジュールplugがある。
  • 関数plugはconnとオプションを受け取り、何かしらの処理を加えて、加工したconnを返す。
  • モジュールplugはinit/1とcall/2を定義し、initはオプションの初期化を行う。callはconnを更新して返す。

 

Plug公式Hello world

plugのREADMEに記載されているHello worldプログラムが何をしているのか少し見てみました。

plug/README.md at master · elixir-plug/plug · GitHub

 

まずはモジュールplugの用意。

defmodule MyPlug do
  import Plug.Conn

  def init(options) do
    # initialize options

    options
  end

  def call(conn, _opts) do
    conn
    |> put_resp_content_type("text/plain")
    |> send_resp(200, "Hello world")
  end
end

 

そしてサーバーの起動。

$ iex -S mix
iex> c "path/to/file.ex"
[MyPlug]
iex> {:ok, _} = Plug.Adapters.Cowboy.http MyPlug, []
{:ok, #PID<...>}

 

これでポート4000でサーバーが立ち上がり、callで定義されている”Hellow world”の出力が行われる。

Plug.Adapters.Cowboy.http MyPlug, []の部分は、中身ではCowboyモジュールのhttp_startメソッドを呼び出していて、第2引数にplugを渡している。

それが以下の部分。

https://github.com/elixir-plug/plug/blob/master/lib/plug/adapters/cowboy.ex#L185

apply(:cowboy, :"start_#{scheme}", args(scheme, plug, opts, cowboy_options))

 

applyというのはモジュールのメソッドを呼び出す関数。

#{scheme}には「http」が渡ってきているので、

cowboyモジュールのstart_httpが呼ばれ、第2引数にplugが渡されている事が分かる。

 

Cowboyが中身で何をしているのか自分はよくわかっていないが、つまるところWebサーバーの出力に必要な情報をPlugを使って定義しているという事なんだろうと思う。

 

なんとなくわかってきた気がする。

調べながら徐々に加筆していこうと思います。

 

アプリケーションモジュールの設定

Elixirs Shoolの以下の項目も見てみましたが、なんかよく分かりません。

https://elixirschool.com/jp/lessons/specifics/plug/#プロジェクトのアプリケーションモジュールの設定 

 

こういうコードを用意しろと書いてあります。何をやっているんだろうか。

defmodule Example do
  use Application
  require Logger

  def start(_type, _args) do
    children = [
      Plug.Adapters.Cowboy.child_spec(:http, Example.HelloWorldPlug, [], port: 8080)
    ]

    Logger.info "Started application"

    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

 

まずここ。

    children = [
      Plug.Adapters.Cowboy.child_spec(:http, Example.HelloWorldPlug, [], port: 8080)
    ]

Plug.Adapters.Cowboy.child_specの中身を見てみます。(つづく)

 

 

参考サイト

Plug · Elixir School