2

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
1
  • 2
    Maybe via rescue_from? Commented Mar 1, 2021 at 17:21

1 Answer 1

4

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
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for this explanation, very helpful!
Do I need to assign the variable req in the rescue_stripe_errors function? Also, if the error block in handle_request returns then does that get assigned to the payment_capture variable in capture? Will this cause the additional render in capture?
I changed it a little bit to return an array instead of hash from rescue_stripe_errors ... so hopefully it's more clear that this method is returning 2 values (the response and the. error). The variable names inside this method don't really matter. Conceptually it's just returning [success_value, error] and one of those will be nil ... after you call rescue_stripe_errors you can figure out which is nil and proceed accordingly

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.