I want to validate uris like:
http://vk.com
http://semantic-ui.com/collections/menu.html
https://translate.yandex.ru/?text=poll&lang=en-ru
and not
www.vk.com
abdeeej
http://vk
but haven't found either package of native code implementation for it.
How can I do that?
All of those are technically valid URLs according to the spec so URI.parse/1 returns a %URI{} struct for all, but if you want to reject domains without a scheme and a dot in the host, you can do:
valid? = fn url ->
  uri = URI.parse(url)
  uri.scheme != nil && uri.host =~ "."
end
Test:
urls = [
  "http://vk.com",
  "http://semantic-ui.com/collections/menu.html",
  "https://translate.yandex.ru/?text=poll&lang=en-ru",
  "www.vk.com",
  "abdeeej",
  "http://vk"
]
urls |> Enum.map(valid?) |> IO.inspect
Output:
[true, true, true, false, false, false]
                        This solution is more complete:
  def validate_url(changeset, field, opts \\ []) do
    validate_change(changeset, field, fn _, value ->
      case URI.parse(value) do
        val(%URI{scheme: nil}) ->
          "is missing a scheme (e.g. https)"
        %URI{host: nil} ->
          "is missing a host"
        %URI{host: host} ->
          case :inet.gethostbyname(Kernel.to_charlist(host)) do
            {:ok, _} -> nil
            {:error, _} -> "invalid host"
          end
      end
      |> case do
        error when is_binary(error) -> [{field, Keyword.get(opts, :message, error)}]
        _ -> []
      end
    end)
  end
Cribbed from https://gist.github.com/atomkirk/74b39b5b09c7d0f21763dd55b877f998
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With