Papillon6814

Papillon6814

What's the best way of handling error?

Hello.

I’m a beginner programmer from Japan.

I’m in trouble of handling error…

auth_controller.ex

def signup(conn, params) do
    url = @db_domain_url <> @api_url <> @signup_url
    try do
      attrs = Poison.encode!(params)
    rescue
      _ -> 
        render("error.json", "Failed to encode json from client", 2000)
    end

    try do
      {:ok, response} = HTTPoison.post(url, attrs, @content_type)
    rescue
      _ -> 
        render("error.json", "POST Request failed", 3000)
    end

    try do
      body = Poison.decode!(response.body)
    rescue
      _ ->
        render("error.json", "Failed to decode json from DB server", 2001)
    end

    render("show.json", body)
  end

auth_view.ex

defmodule PappapWeb.AuthView do
  use PappapWeb, :view

  def render("show.json", %{} = body) do
    body
  end

  def render("error.json", msg, error_no) do
    %{
      "result" => false,
      "reason" => msg,
      "error_no" => error_no
    }
  end
end

Those are codes in my Request-Handling server. It receives requests from ios, and then it fetches data from Database server.
To prevent crash of ios, I want to handle error in good ways. But I don’t know how to do that. With those codes, my server did not start due to an error.

== Compilation error in file lib/pappap_web/controllers/auth_controller.ex ==
** (CompileError) lib/pappap_web/controllers/auth_controller.ex:20: undefined function attrs/0
    (elixir 1.10.3) src/elixir_locals.erl:114: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3
    (stdlib 3.13) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir 1.10.3) lib/kernel/parallel_compiler.ex:304: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

I know it is a problem of variable scopes… but I’m not sure what is the best way to handle errors…

Help me!

Most Liked

hauleth

hauleth

with {:req, {:ok, attrs}} <- {:req, Poison.encode(params)},
     {:http, {:ok, response}} <- {:http, HTTPoison.post(url, attrs, @content_type)},
     {:resp, {:ok, body}} <- {:resp, Poison.decode(response.body)}
do
  render("show.json", body)
else
  {:req, _} -> render("error.json", "Failed to encode json from client", 2000)
  {:http, _} -> render("error.json", "POST Request failed", 3000)
  {:resp, _} -> render("error.json", "Failed to decode json from DB server", 2001)
end

Alternatively you can use action_fallback/1 for handling errors:

# Handler
with {:req, {:ok, attrs}} <- {:req, Poison.encode(params)},
     {:http, {:ok, response}} <- {:http, HTTPoison.post(url, attrs, @content_type)},
     {:resp, {:ok, body}} <- {:resp, Poison.decode(response.body)}
do
  render("show.json", body)
end

# Action fallback

def call(conn, {:req, _}), do: render("error.json", "Failed to encode json from client", 2000)
def call(conn, {:http, _}), do: render("error.json", "POST Request failed", 3000)
def call(conn, {:resp, _}), do: render("error.json", "Failed to decode json from DB server", 2001)
hauleth

hauleth

Because exceptions are mean to be used in exceptional cases, not when you need flow control. All of the cases mentioned above are expected cases, not exceptions.

kokolegorille

kokolegorille

It is not a common pattern to use try and catch clause… and Yes, it’s a scoping problem.

But before solving the scope, You might want to refactor a little bit.

If You think something can go wrong, You could use the “soft” Poison.encode, instead of Poison.encode!, which raise an error.

You just have to deal with {:ok, result}, or {:error, reason}.

And because You have multiple conditions, I would be tempted to use with.

with {:ok, attrs} <- Poison.encode(params),
  {:ok, response} <- HTTPoison.post(url, attrs, @content_type),
  {:ok, body} <- Poison.decode(response.body) do
  render("show.json", body)
else
  ... # Manage errors here!
end

I would always try to avoid try and catch

Where Next?

Popular in Questions Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
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
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
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
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
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

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
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
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
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
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement