verkhovin

verkhovin

How to handle error handling boilerplate

Hi guys!
Want to open here another discussion about error handling concepts in Elixir because it looks like I really stuck here by myself.

My question is about errors that are related to users interactions, where you can’t just “Fail fast and forget / Let it crash” but need to respond with some appropriate error message.
Elixir community’s standard is to return tuples like {:error, reason} when something goes wrong during function execution. Overall, it looks good at the first sight.
But at some point, I noticed that to handle this approach I have to write tons of case or with really often just to check that underlying call didn’t return this {:error, reason} tuple.

Consider an example of a multilayered application (like ControllerBusiness Logic → database CRUDs). If there is some expected error that occurs on the layer of CRUDs, I will need to have a case to catch this error on a Business Logic layer and pass it to Controller. After that, I need to have another case on the Controller’s layer. And it becomes even worse if you have more than 3 layers there, or your business logic includes something more than just a call to CRUD layer.
Maybe I really missed something but it seems to me that this approach makes you write a lot of boilerplate.

I’m actually from Java world and it would be quite natural for me to resolve this issue by throwing (raising) an exception from the CRUDs level and catch in on the Controller level. But if I understand correctly, exceptions in Elixir philosophy are more about unexpected errors that should be handled by this “Let it crash” way.

My question still is: is it normal and common way to write elixir code having this error checks (case/with) on every layer of the application?

I can provide some naive code example if my thoughts are not clear.

Most Liked

sezaru

sezaru

I’m not sure if I follow you when you say you cannot redirect them all to the controller.

Let’s say you have a function CRUD.get that returns {:ok, value} or :error, reason} and that reason can be multiple types of errors.

Now let’s say you want to redirect the errors to the controller from your business logic and handle the :ok case, if you redirect something to the controller via this function return, you can simply do something like:

with {:ok, value} <- CRUD.get() do
  # Do something with value
end

This will handle the :ok case and redirect all the other ones.

If you need to call a function to redirect it to the controller, you can do something like:

with {:ok, value} <- CRUD.get() do
  # Do something with value
else
  {:error, reason} -> Controller.redirect({:error, reason})
end

or

case  CRUD.get() do
 {:ok, value} ->
    # Do something with value

 {:error, reason} -> 
    Controller.redirect({:error, reason})
end

In all these cases you don’t need to have a case for each error tuple, you can simply pattern match all of them.

Now at the Controller, if you want to handle each one of the errors, then you will need to use case or function pattern match to handle it, but that would be the same with java handling the catch cases.

Doesn’t that solves the issue or am I missed the point entirely of what the real problem is in your case?

joaquinalcerro

joaquinalcerro

You can also check this interesting post from @michalmuskala - Error Handling in Elixir Libraries | Michał Muskała

hauleth

hauleth

I would say that it depends on the requirements and what kind of error is that:

  • if there is reasonable way to do fallback, for example fetching data failed, but we can return cached result or something like that, then using ok/error tuple is ok
  • if there is no reasonable way to fallback, for example there is no user in the DB for given ID, then I would throw and let Plug.Exception do it’s thing

Where Next?

Popular in Questions Top

qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call t...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement