Skip to content

Instantly share code, notes, and snippets.

@atomkirk
Last active February 14, 2024 07:20
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atomkirk/74b39b5b09c7d0f21763dd55b877f998 to your computer and use it in GitHub Desktop.
Save atomkirk/74b39b5b09c7d0f21763dd55b877f998 to your computer and use it in GitHub Desktop.
validate url in elixir

Here's an ecto changeset validation for urls:

  @doc """
  validates field is a valid url

  ## Examples
    iex> Ecto.Changeset.cast(%ZB.Account{}, %{"website" => "https://www.zipbooks.com"}, [:website])
    ...> |> Utils.Changeset.validate_url(:website)
    ...> |> Map.get(:valid?)
    true

    iex> Ecto.Changeset.cast(%ZB.Account{}, %{"website" => "http://zipbooks.com/"}, [:website])
    ...> |> Utils.Changeset.validate_url(:website)
    ...> |> Map.get(:valid?)
    true

    iex> Ecto.Changeset.cast(%ZB.Account{}, %{"website" => "zipbooks.com"}, [:website])
    ...> |> Utils.Changeset.validate_url(:website)
    ...> |> Map.get(:valid?)
    false

    iex> Ecto.Changeset.cast(%ZB.Account{}, %{"website" => "https://zipbooks..com"}, [:website])
    ...> |> Utils.Changeset.validate_url(:website)
    ...> |> Map.get(:valid?)
    false
  """
  def validate_url(changeset, field, opts \\ []) do
    validate_change changeset, field, fn _, value ->
      case URI.parse(value) do
        %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
@anthonator
Copy link

πŸ‘ πŸ‘ πŸ‘

@tensiondriven
Copy link

@atomkirk
Copy link
Author

oh good find!

Copy link

ghost commented Nov 12, 2019

πŸ†πŸ†πŸ†

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment