1
votes

I'm not sure how best to do this:

I've got a function that looks up an IP and returns the country it's from.

country = Geolix.lookup(remote_ip).country.registered_country.name

Sometimes it fails, and in that case, none of the array keys are defined.

In other languages, I might do something like:

try do
  country = Geolix.lookup(remote_ip).country.registered_country.name
rescue
  country = nil
end

I'm really struggling to get the syntax right. This also doesn't feel very 'clean'; is there a better way?

2

2 Answers

4
votes

You can also use case ... do with pattern matching, if the result of the case has all the keys you need it matches the first one, where you extract the name, if not it means whatever you got from Geolix.lookup/1 doesn't conform to the pattern you want and you return nil

country = 
       case Geolix.lookup(remote_ip) do
          %{country: %{registered_country: %{name: name}}} -> name
          _ -> nil
       end
1
votes

You don’t do this with try macro. It is not designed to control the flow.

I’d recommend using Kernel.SpecialForms.with/1:

country =
  with %{country: country} <- Geolix.lookup(remote_ip),
       %{registered_country: rc} <- country,
       %{name: name} <- rc, do: name

Kernel.get_in/2 might also work:

get_in Geolix.lookup(remote_ip), ~w[country registered_country name]a

FWIW, here is the correct Kernel.SpecialForms.try/1 syntax:

country =
  try do
    Geolix.lookup(remote_ip).country.registered_country.name
  rescue
    _ -> nil
  end

The answer provided by @m3characters is also very good.