Hey, i just read there is a better way to handle errors than this:
with {:service, {:ok, resp}} <- {:service, call_service(data)},
{:decode, {:ok, decoded}} <- {:decode, Jason.decode(resp)},
{:db, {:ok, result}} <- {:db, store_in_db(decoded)} do
:ok
else
{:service, {:error, error}} ->
# Do something with service error
{:decode, {:error, error}} ->
# Do something with json error
{:db, {:error, error}} ->
# Do something with db error
end
It says to avoid else blocks in with statements:
defmodule MyApp.Error do
defexception [:code, :msg, :meta]
def new(code, msg, meta) when is_binary(msg) do
%__MODULE__{code: code, msg: msg, meta: Map.new(meta)}
end
def not_found(msg, meta \\ %{}) do
new(:not_found, msg, meta)
end
def internal(msg, meta \\ %{}) do
new(:internal, msg, meta)
end
end
def main do
with {:ok, response} <- call_service(data),
{:ok, decoded} <- decode(response),
{:ok, result} <- store_in_db(decoded) do
:ok
end
end
# We wrap the result of Jason.decode in our own custom error type
defp decode(resp) do
with {:error, e} <- Jason.decode(resp) do
{:error, Error.internal("could not decode: #{inspect resp}")}
end
end
I dont quite understand how this works, do i need to create a wrapper for every of my funcions that handles the error case? Thanks
So much bloat and coming up with names