I’m no Elixir guru but probably something like this
def parse_url(url) do
{:ok, URI.parse(url)}
|> validate_profile()
|> validate_stuff()
end
defp validate_profile({:ok, url} = data) do
# validate here
# if ok
data
# if error
{:error, "profile validation failed"}
end
defp validate_stuff({:ok, url} = data) do
# validate here
# if ok
data
# if error
{:error, "stuff validation failed"}
end
defp validate_stuff(x), do: x
In case you need to return nil or string if it’s valid use something like
def parse_url(url) do
{:ok, URI.parse(url)}
|> validate_profile()
|> validate_stuff()
|> case do
{:ok, url} -> url
_ -> nil
end
end
def url_valid?(url) do # use a ? postfix sigil if you intend it to output a boolean value
%{path: path, host: host} = URI.parse(url)
cond do
is_nil(path) || is_nil(host) -> false
String.contains?(path, "/../") -> false # path =~ "/../" also good
match?({:error, _}, :inet.parse_address...) -> false
true -> true
end
end
if you want to output more descriptive errors, I recommend using a with statement, though at some level of complexity you might have to give up on with statements and settle with something ugly. No sense in trying to make something real-world ugly pretty, in the end. Let the code appropriately reflect the system’s messiness.
Don’t forget to spot test this thing. Unless you need more descriptiveness (in which case you should use :ok/{:error, _}) Outputting a true/false instead of valid/invalid is a better choice because it integrates directly with assert and refute.