Current section

Files

Jump to
finch lib finch request.ex
Raw

lib/finch/request.ex

defmodule Finch.Request do
@moduledoc """
A request struct.
"""
@enforce_keys [:scheme, :host, :port, :method, :path, :headers, :body, :query]
defstruct [:scheme, :host, :port, :method, :path, :headers, :body, :query]
@atom_methods [
:get,
:post,
:put,
:patch,
:delete,
:head,
:options
]
@methods [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"HEAD",
"OPTIONS"
]
@atom_to_method Enum.zip(@atom_methods, @methods) |> Enum.into(%{})
@typedoc """
An HTTP request method represented as an `atom()` or a `String.t()`.
The following atom methods are supported: `#{Enum.map_join(@atom_methods, "`, `", &inspect/1)}`.
You can use any arbitrary method by providing it as a `String.t()`.
"""
@type method() :: :get | :post | :head | :patch | :delete | :options | :put | String.t()
@typedoc """
A Uniform Resource Locator, the address of a resource on the Web.
"""
@type url() :: String.t() | URI.t()
@typedoc """
Request headers.
"""
@type headers() :: Mint.Types.headers()
@typedoc """
Optional request body.
"""
@type body() :: iodata() | {:stream, Enumerable.t()} | nil
@type t :: %Finch.Request{}
@doc false
def request_path(%{path: path, query: nil}), do: path
def request_path(%{path: path, query: query}), do: "#{path}?#{query}"
@doc false
def build(method, url, headers, body) do
{scheme, host, port, path, query} = parse_url(url)
%Finch.Request{
scheme: scheme,
host: host,
port: port,
method: build_method(method),
path: path,
headers: headers,
body: body,
query: query
}
end
@doc false
def parse_url(url) when is_binary(url) do
url |> URI.parse() |> parse_url()
end
def parse_url(%URI{} = parsed_uri) do
normalize_uri(parsed_uri)
end
defp normalize_uri(parsed_uri) do
normalized_path = parsed_uri.path || "/"
scheme = normalize_scheme(parsed_uri.scheme)
{scheme, parsed_uri.host, parsed_uri.port, normalized_path, parsed_uri.query}
end
defp build_method(method) when is_binary(method), do: method
defp build_method(method) when method in @atom_methods, do: @atom_to_method[method]
defp build_method(method) do
supported = Enum.map_join(@atom_methods, ", ", &inspect/1)
raise ArgumentError, """
got unsupported atom method #{inspect(method)}.
Only the following methods can be provided as atoms: #{supported}.
Otherwise you must pass a binary.
"""
end
defp normalize_scheme(scheme) do
case scheme do
"https" ->
:https
"http" ->
:http
scheme ->
raise ArgumentError, "invalid scheme #{inspect(scheme)}"
end
end
end