# `URL`
[🔗](https://github.com/kipcole9/url/blob/v2.0.3/lib/url.ex#L1)

Functions for parsing URLs.

This module provides functions for parsing URLs. It is modelled on
Elixir's `URI` module but will also parse scheme-specific URIs such
as [geo](https://tools.ietf.org/rfc/rfc5870), [data](https://tools.ietf.org/html/rfc2397)
[tel](https://tools.ietf.org/html/rfc3966), [mailto](https://tools.ietf.org/html/rfc6068),
and [uuid](https://tools.ietf.org/html/draft-kindel-uuid-uri-00).

The primary API is `new/1`, which returns a `t:t/0` struct with the
same shape as `t:URI.t/0` plus a `:parsed_path` holding the parsed
scheme-specific data (`URL.Geo`, `URL.Data`, `URL.Tel`, `URL.Mailto`
or `URL.UUID`), or `nil` for any other scheme. `new!/1` raises
instead of returning an error tuple, `to_string/1` reverses the
parse and `parse_query_string/1` decodes a query into a map.
No function in this module raises on malformed input.

# `t`

```elixir
@type t() :: %URL{
  authority: nil | binary(),
  fragment: nil | binary(),
  host: nil | binary(),
  parsed_path: uri_type(),
  path: nil | binary(),
  port: nil | :inet.port_number(),
  query: nil | binary(),
  scheme: nil | binary(),
  userinfo: nil | binary()
}
```

# `uri_type`

```elixir
@type uri_type() ::
  nil | URL.Data.t() | URL.Geo.t() | URL.Tel.t() | URL.UUID.t() | URL.Mailto.t()
```

# `new`

```elixir
@spec new(url :: binary()) :: {:ok, t()} | {:error, {module(), String.t()}}
```

Parses a string url and returns a `t:URL.t/0` struct that
has the same shape as Elixir's `t:URI.t/0` with the
addition of the `parsed_path` key.

### Arguments

* `url` is a binary representation of a URL.

### Returns

* `{:ok, URL.t()}` or

* `{:error, {exception, reason}}`. `exception` is `URI.Error` when
  the URL is not syntactically valid, `URL.Parser.ParseError` when the
  scheme-specific path cannot be parsed and `ArgumentError` when `url`
  is not a binary.

### Examples

    iex> URL.new("geo:48.198634,-16.371648,3.4;crs=wgs84;u=40.0")
    {:ok,
      %URL{
        authority: nil,
        fragment: nil,
        host: nil,
        parsed_path: %URL.Geo{
          alt: 3.4,
          lat: 48.198634,
          lng: -16.371648,
          params: %{"crs" => "wgs84", "u" => 40.0}
        },
        path: "48.198634,-16.371648,3.4;crs=wgs84;u=40.0",
        port: nil,
        query: nil,
        scheme: "geo",
        userinfo: nil
      }
    }

    iex> URL.new("geo:48.198634,--16.371648,3.4;crs=wgs84;u=40.0")
    {:error,
     {URL.Parser.ParseError,
      "expected an string of digits while processing lat inside alt inside geo data. Detected on line 1 at \"-16.371648,3.4;crs=w\" <> ..."}}

    iex> URL.new "/invalid_greater_than_in_path/>"
    {:error,
     {URI.Error,
      "cannot parse due to reason invalid_uri: \">\""}}

    iex> URL.new(:not_a_url)
    {:error, {ArgumentError, "expected a binary URL, got: :not_a_url"}}

# `new!`

```elixir
@spec new!(url :: binary()) :: t() | no_return()
```

Parses a string url and returns a `t:URL.t/0` struct that
has the same shape as Elixir's `t:URI.t/0` with the
addition of the `parsed_path` key, or raises an exception.

### Arguments

* `url` is a binary representation of a URL.

### Returns

* `t:URL.t/0` or

* raises an exception.

### Examples

    iex> URL.new!("geo:48.198634,-16.371648,3.4;crs=wgs84;u=40.0")
    %URL{
      authority: nil,
      fragment: nil,
      host: nil,
      parsed_path: %URL.Geo{
        alt: 3.4,
        lat: 48.198634,
        lng: -16.371648,
        params: %{"crs" => "wgs84", "u" => 40.0}
      },
      path: "48.198634,-16.371648,3.4;crs=wgs84;u=40.0",
      port: nil,
      query: nil,
      scheme: "geo",
      userinfo: nil
    }

# `parse_query_string`

```elixir
@spec parse_query_string(String.t() | nil | map() | {:error, {module(), binary()}}) ::
  map() | {:error, {module(), binary()}}
```

Parse and percent decode a URL query string.

### Arguments

* `query` is a query string, a `t:URL.t/0` (or any map with a
  `:query` key) whose query is parsed, or an `{:error, reason}`
  tuple which is returned unchanged so this function can be
  piped after `new/1`.

### Returns

* Either a map of query params (an empty map when the query is `nil`) or

* an `{:error, {exception, reason}}` tuple.

### Examples

    iex> URL.parse_query_string("url=http%3a%2f%2ffonzi.com%2f&name=Fonzi&mood=happy&coat=leather")
    %{
      "coat" => "leather",
      "mood" => "happy",
      "name" => "Fonzi",
      "url" => "http://fonzi.com/"
    }

    iex> mailto = "mailto:user@%E7%B4%8D%E8%B1%86.example.org?subject=Test&body=NATTO"
    iex> URL.new!(mailto) |> URL.parse_query_string()
    %{"body" => "NATTO", "subject" => "Test"}

    iex> URL.new!("geo:48.198634,-16.371648") |> URL.parse_query_string()
    %{}

# `to_string`

```elixir
@spec to_string(t()) :: String.t()
```

Returns the string representation of the given URL struct (t:t/0).

This function delegates to `URI.to_string/1`.

### Arguments

* `url` is any `t:URL.t/0`.

### Returns

* a string representation of the URL.

### Examples

    iex> {:ok, geo_url} = URL.new("geo:48.198634,-16.371648,3.4;crs=wgs84;u=40.0")
    iex> URL.to_string(geo_url)
    "geo:48.198634,-16.371648,3.4;crs=wgs84;u=40.0"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
