ruby-on-railsapifullcontact

Handling third party API 400/500 responses in my RAILS controllers


I'm learning how to implement third party APIs into my rails app but struggling handling error responses.

More specifically, I'm trying to implement Full Contact API with the gem fullcontact-api-ruby. I've sorted out the authentication with my API Key and have made some request via the console using the gem methods without a problem.

I'm now trying to use the API wrapper methods inside a Profiles Controller. The idea is to:

  1. Send to the controller an email as a parameter
  2. The Full Contact API method 'person()' will retrieve information associated to that email
  3. A profile object will be created populating its attributes using the fetched API data.
  4. If there's no data available for that email, there's a bad request or server error then a flash error and a redirection will happen.

I started writing a code like:

  # controllers/profiles_controller.rb
  def create
    @intel = FullContact.person(email: params[:email])
    if @intel[:status].to_s[0] != "2"
      flash[:error] = @intel[:status] 
      redirect_to profiles_path
    else
      # Code to create and populate a Profile instance
  end

As success responses have status codes in the 200s I assumed I would extract the code from the Json object and check if it starts with 2, in which case I'd proceed with the instance creation. This sort of works if the response is OK as I'm able to work with a Json object stored in @intel. However, when the response is in the 400s,500s Rails triggers an exception that crashes Rails not allowing me to work with any JSON object:

FullContact::NotFound in ProfilesController#create
GET https://api.fullcontact.com/v2/person.json?apiKey=MY_API_KEY&email=THE_EMAIL_IM_USING_AS_PARAMETER: 404

I'm clearly doing something wrong. I've tried avoiding the raised exception with rescue StandardError => e which works but I wonder what's the proper way to handle this errors in my controller. Any help?

---UPDATE 1 TRYING STEVE SOLUTION--

If I rescue the exception just after the request like this:

  def create
    @intel = FullContact.person(email: params[:email])
    rescue FullContact::NotFound

    if @intel.nil?
      flash[:error] = "Can't process request try again later"
      redirect_to profiles_path
    else
      # Code to create and populate a Profile instance
  end

@intel is set to nil (i.e. not set to the response JSON object). I figured I just change the conditional to check if @intel is nil but for some weird reason when the response is successful and @intel is set to a JSON object the first conditional doesn't lead to the method to the object creation. Not sure how to set @intel to the JSON response even when the response has failed.


Solution

  • The idea of the rescue block is to define the actions that happen when you rescue from the error.

    The correct way to structure your method would be...

    def create
      @intel = FullContact.person(email: params[:email])
      # Code to create and populate a Profile instance
    
    rescue FullContact::NotFound   
      flash[:error] = "Can't process request try again later"
      redirect_to profiles_path
    end 
    

    The code that appears after the rescue is executed when rescued, otherwise ignored.

    the format is

    begin
      # normal code which may or may not encounter a raised error, if no
      #  raised error, it continues to normal completion
    rescue 
      # code that is only executed if there was a rescued error
    ensure
      # code that always happens, regardless of rescue or not, could be 
      # used to ensure necessary cleanup happens even if an exception raised
    end
    

    A method is by itself a full begin block, so doesn't need the begin and end in the above format outline.

    You don't need an ensure block, just added that to show that capability exists. There's also the possibility to use else with rescue but that's for another day :)