Home > Back-end >  Rails 7 rescue API error and stil show the view
Rails 7 rescue API error and stil show the view

Time:10-21

In my Rails 7 app I'm using several 3rd parties API to provide fetch data. Each time I'm receiving an error I've to rescue with nil to still be able to display redirect user to desired page, e.g.:

# lib/custom_api.rb

module CustomApi
  extend self

  def fetch_transactions(user_id)
    client.transactions.list(user_id:)

  # rescue from custom error
  rescue Errors::NotFoundError
    nil
  end
end

# transactions_controller.rb

class TransactionsController < ApplicationController
  def index
    transaction_list = CustomApi.fetch_transactions(current_user.id)

    if transaction_list
      @transactions = transaction_list
    else
      @transactions = transaction_list
      flash[:alert] = 'No transactions'
    end
  end
end

# views/transactions/index.html.erb

<%= turbo_frame_tag 'transactions' do %>
  <%= render partial: 'table_headers' %>
  <%= render Transactions::TableComponent.new(records: @transactions) if @transactions %>
<% end %>

Everything works well but I've got 50 endpoints where I need to include rescue Errors::NotFoundError and I don't think it's super sufficient to to repeat this line 50 times. Is there a way to avoid that?

CodePudding user response:

In general, using Rescuable is the Rails' way for rescuing from exception in a centralized manner.

Add this to your ApplicationController:

rescue_from Errors::NotFoundError, with: :handle_not_found_error_from_external_api

private

def handle_not_found_error_from_external_api
  # handle the error in a generalized way, for example, by returning a response
  # that renders a modal or a toast. 
end

And remove these lines from your CustomApi:

# rescue from custom error
rescue Errors::NotFoundError
  nil

CodePudding user response:

You can use class inheritance to accomplish what you need:

class CustomApi
  def self.fetch(args)
    self.new.do_fetch(args)

  # rescue from custom error
  rescue Errors::NotFoundError
    nil
  end
end

and then for the transaction API:

class CustomTransactionApi < CustomApi
  def do_fetch(args)
    client.transactions.list(args[:user_id])
  end
end

For instance, if you have another API for messages:

class CustomMessageApi < CustomApi
  def do_fetch(args)
    client.messages.list(args[:user_id])
  end
end

And then your controller will be:

class TransactionsController < ApplicationController
  def index
    @transaction_list = CustomTransactionApi.fetch({user_id: current_user.id})
    flash[:alert] = 'No transactions' if @transaction_list.blank?
  end
end
  • Related