Skip to main content

lib/quack_db/uri.ex

defmodule QuackDB.URI do
  @moduledoc """
  URI normalization for Quack HTTP endpoints.
  """

  alias QuackDB.Error

  @spec normalize(String.t()) :: {:ok, URI.t()} | {:error, Error.t()}
  def normalize(value) when is_binary(value) do
    value
    |> ensure_scheme()
    |> URI.parse()
    |> normalize_parsed()
  end

  defp ensure_scheme(value) do
    if String.contains?(value, "://") do
      value
    else
      "http://" <> value
    end
  end

  defp normalize_parsed(%URI{scheme: "quack"} = uri) do
    normalize_http(%{uri | scheme: "http"})
  end

  defp normalize_parsed(%URI{scheme: scheme} = uri) when scheme in ["http", "https"] do
    normalize_http(uri)
  end

  defp normalize_parsed(%URI{scheme: scheme}) do
    error(:invalid_uri, "unsupported Quack URI scheme #{inspect(scheme)}")
  end

  defp normalize_http(%URI{host: host} = uri) when is_binary(host) and host != "" do
    {:ok, %{uri | path: normalize_path(uri.path)}}
  end

  defp normalize_http(_uri) do
    error(:invalid_uri, "Quack URI must include a host")
  end

  defp normalize_path(nil), do: "/quack"
  defp normalize_path(""), do: "/quack"
  defp normalize_path("/"), do: "/quack"
  defp normalize_path(path), do: path

  defp error(code, message) do
    {:error, Error.new(code, message, source: :client)}
  end
end