Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elixir Meetup #2 Plugのモジュールを一通り使ってみた

Elixir Meetup #2 Plugのモジュールを一通り使ってみた

Genki Sugawara

March 21, 2016
Tweet

More Decks by Genki Sugawara

Other Decks in Technology

Transcript

  1. Plugͱ͸ https:/ /hexdocs.pm/plug/ Plug is: A specification for composable modules

    between web applications Connection adapters for different web servers in the Erlang VM
  2. Plug.Adapters.Cowboy defmodule ElixirPlugExamples.HttpPlug do import Plug.Conn def init(opts), do: opts

    def call(conn, _opts) do conn |> put_resp_content_type("text/plain") |> send_resp(200, "Hello world") end end Plug.Adapters.Cowboy.http ElixirPlugExamples.HttpPlug, [], port: 9001
  3. Plug.Adapters.Cowboy defmodule ElixirPlugExamples.HttpsPlug do import Plug.Conn def init(opts), do: opts

    def call(conn, _opts) do conn |> put_resp_content_type("text/plain") |> send_resp(200, "Hello world") end end Plug.Adapters.Cowboy.https ElixirPlugExamples.HttpsPlug, [], [ keyfile: Path.join([__DIR__, "server.key"]), certfile: Path.join([__DIR__, "server.crt"]), port: 9001]
  4. Plug.Builder defmodule ElixirPlugExamples.BuilderPlug do use Plug.Builder plug :hello plug :world

    plug :append, "Zzz" plug :resp def hello(conn, _opts) do conn |> assign(:msg, "hello") # stop response #conn |>send_resp(200, "stopped") |> halt end #(ଓ͘)
  5. Plug.Builder #(ଓ͖) def world(conn, _opts) do msg = conn.assigns[:msg] <>

    " world" conn |> assign(:msg, msg) end def append(conn, opts) do msg = conn.assigns[:msg] <> opts conn |> assign(:msg, msg) end def resp(conn, _opts) do conn |> put_resp_content_type("text/plain") |> send_resp(200, conn.assigns[:msg]) end end
  6. Plug.CSRFProtection defmodule ElixirPlugExamples.CSRFProtectionPlug do use Plug.Builder plug Plug.Session, store: :ets,

    key: "_my_app_session", table: :session plug :fetch_session plug Plug.CSRFProtection plug :resp def resp(conn, _opts) do conn |> put_resp_content_type("text/plain") |> send_resp(200, Plug.CSRFProtection.get_csrf_token) end end :ets.new(:session, [:named_table, :public, read_concurrency: true])
  7. Plug.Conn • ίωΫγϣϯ·ΘΓͷجຊతͳػೳͷϞδϡʔϧ • ϦΫΤετ͔Βऔಘ: get_xxx(conn, ...) • Ϩεϙϯεʹ௥Ճ: put_xxx(conn,

    ...) • ͦͷଞηογϣϯૢ࡞ͨ͠ΓɺϢʔβσʔλΛૢ࡞ͨ͠Γ… def call(conn, _opts) do ... end
  8. Plug.Conn %Plug.Conn{ adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{}, before_send: [], body_params:

    %Plug.Conn.Unfetched{aspect: :body_params}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "localhost", method: "GET", owner: #PID<0.248.0>, params: %Plug.Conn.Unfetched{aspect: :params}, path_info: [], peer: {{127, 0, 0, 1}, 56143}, port: 9001, private: %{}, query_params: %Plug.Conn.Unfetched{aspect: :query_params}, query_string: "", #(ଓ͘)
  9. Plug.Conn #(ଓ͖) remote_ip: {127, 0, 0, 1}, req_cookies: %Plug.Conn.Unfetched{aspect: :cookies},

    req_headers: [ {"host", "localhost:9001"}, {"user-agent", "curl/7.43.0"}, {"accept", "*/*"}], request_path: "/", resp_body: nil, resp_cookies: %{}, resp_headers: [ {"cache-control","max-age=0, private, must-revalidate"}], scheme: :http, script_name: [], secret_key_base: nil, state: :unset, status: nil}
  10. Plug.Conn / misc • Adapter: ΞμϓλͷϏϔΠϏΞ • Cookies:ΫοΩʔศརؔ਺ • Query:

    ΫΤϦʔετϦϯάศརؔ਺ • Conn.Status: εςʔλείʔυศརؔ਺ • Unfetched:ύϥϝʔλ΍ϘσΟʔ͕ͳ͍ͱ͖ʹϚοϓ͞ΕΔ஋ • Utils: ίωΫγϣϯؔ࿈ϢʔςΟϦςΟ
  11. Plug.ErrorHandler defmodule ElixirPlugExamples.ErrorHandlerPlug do import Plug.Conn use Plug.ErrorHandler def init(opts),

    do: opts def call(_conn, _opts) do raise "oops" end defp handle_errors(conn, err) do send_resp(conn, conn.status, inspect(err)) end end
  12. Plug.Head defmodule ElixirPlugExamples.HeadPlug do use Plug.Builder plug Plug.Head plug :resp

    def resp(conn, _opts) do IO.inspect conn.method #=> GET conn |> put_resp_content_type("text/plain") |> send_resp(200, "") end end curl -XHEAD http://localhost:9001
  13. Plug.MIME IO.inspect Plug.MIME.extensions("text/html") #=> ["html", "htm"] IO.inspect Plug.MIME.extensions("application/json") #=> ["json"]

    IO.inspect Plug.MIME.extensions("foo/bar") #=> [] IO.inspect Plug.MIME.path("index.html") #=> "text/html" IO.inspect Plug.MIME.type("txt") #=> "text/plain" IO.inspect Plug.MIME.type("foobarbaz") #=> "application/octet-stream" IO.inspect Plug.MIME.valid?("text/plain") #=> true IO.inspect Plug.MIME.valid?("foo/bar") #=> false
  14. Plug.MethodOverride defmodule ElixirPlugExamples.MethodOverridePlug do use Plug.Builder plug Plug.Parsers, parsers: [:urlencoded,

    :multipart] plug Plug.MethodOverride plug :resp def resp(%Plug.Conn{method: "PUT"} = conn, _opts) do conn |> put_resp_content_type("text/plain") |> send_resp(200, "PUT") end end curl -d _method=PUT http://localhost:9001
  15. Plug.Parsers defmodule ElixirPlugExamples.ParsersPlug do use Plug.Builder plug Plug.Parsers, parsers: [:urlencoded,

    :multipart, :json], json_decoder: Poison # required plug :resp def resp(conn, _opts) do conn |> put_resp_content_type("text/plain") |> send_resp(200, inspect(conn.body_params)) end end curl -H "Content-type: application/json" -X POST \ -d '{"user":{"first_name":"firstname"}}' localhost:9001
  16. Plug.RequestId defmodule ElixirPlugExamples.RequestIdPlug do use Plug.Builder plug Plug.RequestId plug :resp

    def resp(conn, _opts) do conn |> put_resp_content_type("text/plain") |> send_resp(200, get_resp_header(conn, "x-request-id")) #=> "emv6tkni35sbvl38udbc4qvfhalgvfpj" end end
  17. Plug.Router defmodule ElixirPlugExamples.RouterPlug do use Plug.Router plug :match plug :dispatch

    get "/hello" do send_resp(conn, 200, "world") end get "/hello/r*glob" do send_resp(conn, 200, "route after /hello: #{inspect glob}") end get "/hello/:name" do send_resp(conn, 200, "hello #{name}") end #(ଓ͘)
  18. Plug.Router #(ଓ͖) match "/foo/:bar" when byte_size(bar) <= 2, via: :get

    do send_resp(conn, 200, "hello world #{inspect(bar)}") end match "/foo/bar", via: :get do send_resp(conn, 200, "hello world") end #match ["foo", bar], via: :get do # send_resp(conn, 200, "hello world") #end match _ do send_resp(conn, 404, "oops") end end
  19. Plug.Session defmodule ElixirPlugExamples.SessionPlug do use Plug.Builder plug Plug.Session, store: :ets,

    key: "_my_app_session", table: :session plug :fetch_session # required plug :resp def resp(conn, _opts) do count = get_session(conn, :counter) || 0 conn |> put_session(:counter, count + 1) |> put_resp_content_type("text/plain") |> send_resp(200, Integer.to_string(count)) end end :ets.new(:session, [:named_table, :public, read_concurrency: true])
  20. Plug.Static defmodule ElixirPlugExamples.StaticPlug do use Plug.Builder plug Plug.Static, at: "/public",

    from: __DIR__ plug :not_found def not_found(conn, _) do send_resp(conn, 404, "not found") end end
  21. Plug.Test defmodule ElixirPlugExamplesTest do use ExUnit.Case, async: true use Plug.Test

    alias ElixirPlugExamples.HttpPlug test "puts session cookie" do conn = conn(:get, "/") conn = ElixirPlugExamples.HttpPlug.call(conn, []) assert conn.resp_body == "xHello world" end end
  22. Plug.Upload defmodule ElixirPlugExamples.UploadPlug do use Plug.Builder plug Plug.Parsers, parsers: [:urlencoded,

    :multipart] plug :resp def resp(conn, _opts) do case conn.params do %{"file" => file} -> IO.inspect file _ -> IO.puts "'file' key not found" end conn |> put_resp_content_type("text/plain") |> send_resp(200, "OK") end end Plug.Upload.start_link
  23. Plugͷࣗ࡞ defmodule JSONHeaderPlug do @behaviour Plug import Plug.Conn def init(opts)

    do opts end def call(conn, _opts) do conn |> put_resp_content_type("application/json") end end