Handle multiple http calls gracefully

Our app makes multiple API calls with Mojito in a LiveView. Sometimes the requests timeout (or maybe some other error) and it crashes the view.

What are some strategies I can use to handle it? The api calls sometimes depend on the results of previous calls.

One thing that comes to mind is:

with {:ok, result_1} <- api_call_1,
     {:ok, result_2} <- api_call_2(result_1[:id]) do
  
  {:ok, assign(socket, result_1: result_1, result_2: result_2)}
else
   {:ok, assign(socket, result_1: nil, result_2: nil)}
end

Then in the template I can somehow handle nil values.

What else is possible? Ideally for a timeout, I want to just retry. Maybe I need to just increase the timeout? Or make the calls with Task.async or a GenServer?

Hi, I don’t know Mojito but let me show you Mint. It creates all requests async and response will come as a message. You can find more information about their architecture and GenServer implementation here

The idea is when you have LiveView you can call GenServer with current implementation for that call and doesn’t care more about it. Or even you can implement that Mint’s architecture in LiveView module. You have to just implement handle_info functions and call api responses. When you get timetout you can do retry or whatever. With this approach your LiveView has to be stable, because all risky work is made outside the process. Dependency with api_call_1 -> api_call_2 is also possible. You call api_call_2 in handle_info function which handle (pattern match) successful response from api_call_1.

Don’t forget when you do some long work inside handle_* functions your LiveView will freeze until you finish it.

1 Like

Thanks. I‘ll try to implement it

I would use a Task.Supervisor, and start a Task with

parent = self()
Task.Supervisor.start_child(MyTaskSup, fn -> 
  with {:ok, result_1} <- api_call_1,
     {:ok, result_2} <- api_call_2(result_1[:id]) do
    send(parent, {:api_calls, {:ok, {result_1, result_2}}})
  else
     error -> send(parent, {:api_calls, error})
  end

And in the live view you can listen for those messages with handle_info.

1 Like

I haven’t done any HTTP in my Elixir projects but last time I tried to use Erlang’s Gun and was very impressed. Loved the granularity and control and I highly recommend it.

Mojito is also a lovely HTTP client. My problem was more how to structure the flow and to make the live_view more robust.