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