styler
styler

Reputation: 16491

How to reuse exception handling in multiple API calls in ruby rails?

I'm trying to reduce the duplicate code I'm using to create and capture payments using the Stripe::PaymentIntents class. Both methods have the same error handling that I'd like to reduce down to one block, but unsure how to achieve this? I'm thinking I need to use the public send method with arguments to cover the calls, but I'm not sure how to return the errors if they would occur or the correct response on success?

Code:

STRIPE_ERRORS = [
      Stripe::CardError,
      Stripe::RateLimitError,
      Stripe::InvalidRequestError,
      Stripe::AuthenticationError,
      Stripe::APIConnectionError,
      Stripe::StripeError
    ].freeze

def capture
      payment_intent_id = params[:payment_intent_id]

      return render_unprocessable_entity('payment_intent_id is required') unless payment_intent_id.present?

      payment_capture = handle_request('capture', payment_intent_id)

      render json: {info: payment_capture.info}, status: :ok
    end

    def handle_request(method, params)
      begin
        req = Stripe::PaymentIntent.send(method, params)
        rescue *STRIPE_ERRORS => e
          Rails.logger.warn(e)
          return render json: { error: e }, status: e.http_status
        rescue StandardError => e
          Rails.logger.error(e)
          return render json: { error: 'Internal server error' }, status: :internal_server_error
      end

      puts "req:: #{req}"

      req
    end

Upvotes: 2

Views: 364

Answers (1)

max pleaner
max pleaner

Reputation: 26768

There are multiple ways to do this. But just to show that you don't need any magic method for it, here's a simple way using a block (anonymous function):

# returns [request, error] array
def rescue_stripe_errors(&block)
  begin
    req = block.call
    [req, nil]
  rescue *STRIPE_ERRORS => e
    [nil, e]
  end
end

Now if you call this you will get a hash with req and error keys. One of them will have a value and the other one will be nil. After calling the function, you can check if the error is nil and proceed accordingly.

def handle_request(method, params)
  req, e = rescue_stripe_errors do
    Stripe::PaymentIntent.send(method, params)
  end

  if e
    Rails.logger.warn(e)
    return render json: { error: e }, status: e.http_status
  end

  puts "req:: #{req}"
  req
end

Upvotes: 4

Related Questions