Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure the Plug.Static without Phoenix

I am trying to figure out how to configure Plug.Static without any other framework (Phoenix, Sugar, etc); just Cowboy, Plug and Elixir. I just don't know how to put things together in the Router.

  plug :match
  plug Plug.Static, at: "/pub", from: :cerber
  plug :dispatch

  get "/" do
    Logger.info "GET /"
    send_resp(conn, 200, "Hello world\n")
  end
  1. Is the declaration of Plug.Static at the right place ? Shouldn't it be after plug :dispatch ?
  2. Do I need to define an additional route
  3. With this declaration:
    1. what is the URL to reach, say index.html?
    2. where on the file system index.html should be located

I'm just lost.

like image 732
mszmurlo Avatar asked Sep 12 '15 20:09

mszmurlo


2 Answers

This is the answer I was looking for.

In the application start method use the Plug.Router with Cowboy:

defmodule HttpServer.Application do
  require Logger
  use Application

  def start(_type, _args) do
    children = [
      {Plug.Adapters.Cowboy2, scheme: :http, plug: HttpServer.Router, options: [port: 4002]}
    ]

    opts = [strategy: :one_for_one, name: HttpServer.Supervisor]

    Supervisor.start_link(children, opts)
  end
end

The router module looks like this:

defmodule HttpServer.Router do
  use Plug.Router

  plug(Plug.Logger)
  plug(:redirect_index)
  plug(:match)
  plug(:dispatch)

  forward("/static", to: HttpServer.StaticResources)

  get "/sse" do
    # some other stuff...
    conn
  end

  match _ do
    send_resp(conn, 404, "not found")
  end

  def redirect_index(%Plug.Conn{path_info: path} = conn, _opts) do
    case path do
      [] ->
        %{conn | path_info: ["static", "index.html"]}

      ["favicon.ico"] ->
        %{conn | path_info: ["static", "favicon.ico"]}

      _ ->
        conn
    end
  end
end

Here requests to "/static" are forwarded to the HttpServer.StaticResources module, but first, the request path is modified for "/" and "/favicon.ico" with plug(:redirect_index). All static files (*.html, *.ico, *.css, *.js etc.) are placed in the default location (project_dir/priv/static).

Finally, the StaticResource module:

defmodule HttpServer.StaticResources do
  use Plug.Builder

  plug(
    Plug.Static,
    at: "/",
    from: :http_server
  )

  plug(:not_found)

  def not_found(conn, _) do
    send_resp(conn, 404, "static resource not found")
  end
end
like image 104
Nikolai Koudelia Avatar answered Oct 03 '22 17:10

Nikolai Koudelia


Take a look at Plug.Router docs for how :match and :dispatch works. :match will try to find a matching route and :dispatch is going to invoke it. This means Plug.Static in your setup will only be invoked if you have a matching route in your router, which doesn't make sense. You want plug Plug.Static before everything. Remember plugs are just functions that are invoked in the order they are declared.

Other than that, your Plug.Static setup seems ok. Your current configuration will serve assets at "/pub", meaning "/pub/index.html" will look for "priv/static/index.html" in your app. More info here: http://hexdocs.pm/plug/Plug.Static.html

like image 37
José Valim Avatar answered Oct 03 '22 18:10

José Valim