Skip to content

Commit

Permalink
Enhance parse_response Method to Improve Error Handling and Logging
Browse files Browse the repository at this point in the history
  • Loading branch information
armando-rodriguez-cko committed Nov 18, 2024
1 parent 7ca3887 commit ef64c60
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 35 deletions.
17 changes: 14 additions & 3 deletions lib/checkout_sdk/api_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,25 @@ def upload(path, authorization, file_request)
end

def parse_response(response)
raise CheckoutApiException, response if response.status < 200 || response.status >= 400
if response.status < 200 || response.status >= 400
raise CheckoutApiException.new(response),
"The API response status code (#{response.status}) does not indicate success."
end

metadata = CheckoutUtils.map_to_http_metadata(response)

body = parse_json_or_contents(response)

body = OpenStruct.new if body.nil?
body = OpenStruct.new(items: body) if body.is_a? Array
body.http_metadata = metadata if body.is_a? OpenStruct
body = OpenStruct.new(items: body) if body.is_a?(Array)

body.http_metadata = metadata if body.is_a?(OpenStruct)

body
rescue JSON::ParserError => e
raise CheckoutApiException.new(response), "Error parsing JSON: #{e.message}"
rescue StandardError => e
raise CheckoutApiException.new(response), "Unexpected error: #{e.message}"
end

def parse_json_or_contents(response)
Expand Down
91 changes: 91 additions & 0 deletions spec/checkout_sdk/api_client_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# frozen_string_literal: true

RSpec.describe CheckoutSdk::ApiClient do
let(:configuration) do
double(
'CheckoutConfiguration',
http_client: Faraday.new,
multipart_http_client: Faraday.new,
logger: Logger.new(STDOUT)
)
end
let(:api_client) { CheckoutSdk::ApiClient.new(configuration, 'https://api.sandbox.checkout.com') }

describe '#parse_response' do
context 'when the response is successful' do
it 'parses the response correctly for valid JSON' do
response = double('Response', status: 200, body: '{"key":"value"}')
allow(CheckoutSdk::CheckoutUtils).to receive(:map_to_http_metadata).and_return({ metadata: 'test' })

parsed_response = api_client.send(:parse_response, response)

expect(parsed_response.key).to eq('value')
expect(parsed_response.http_metadata[:metadata]).to eq('test')
end

it 'returns an OpenStruct object with items for an array response' do
response = double('Response', status: 200, body: '[{"item":"value"}]')
allow(CheckoutSdk::CheckoutUtils).to receive(:map_to_http_metadata).and_return({ metadata: 'test' })

parsed_response = api_client.send(:parse_response, response)

expect(parsed_response.items).to be_an(Array)
expect(parsed_response.items.first['item']).to eq('value')
expect(parsed_response.http_metadata[:metadata]).to eq('test')
end
end

context 'when the response body is nil' do
it 'returns an empty OpenStruct' do
response = double('Response', status: 200, body: nil)
allow(CheckoutSdk::CheckoutUtils).to receive(:map_to_http_metadata).and_return({ metadata: 'test' })

parsed_response = api_client.send(:parse_response, response)

expect(parsed_response).to be_a(OpenStruct)
expect(parsed_response.http_metadata[:metadata]).to eq('test')
end
end

context 'when the response status is less than 200' do
it 'raises a CheckoutApiException' do
response = double('Response', status: 199, body: '{}')

expect do
api_client.send(:parse_response, response)
end.to raise_error(CheckoutSdk::CheckoutApiException, /Invalid response status: 199/)
end
end

context 'when the response status is 400 or higher' do
it 'raises a CheckoutApiException for client errors (4xx)' do
response = double('Response', status: 400, body: '{}')

expect do
api_client.send(:parse_response, response)
end.to raise_error(CheckoutSdk::CheckoutApiException, /Invalid response status: 400/)
end

it 'raises a CheckoutApiException for server errors (5xx)' do
response = double('Response', status: 500, body: '{}')

expect do
api_client.send(:parse_response, response)
end.to raise_error(CheckoutSdk::CheckoutApiException, /Invalid response status: 500/)
end
end

context 'when the response body is invalid JSON' do
it 'raises a CheckoutApiException with JSON parsing error' do

response = double('Response', status: 200, body: '{invalid_json}')

allow(CheckoutSdk::CheckoutUtils).to receive(:map_to_http_metadata).with(response).and_return(OpenStruct.new(metadata: 'test'))

expect do
api_client.send(:parse_response, response)
end.to raise_error(CheckoutSdk::CheckoutApiException, /Error parsing JSON/)
end
end
end
end
36 changes: 36 additions & 0 deletions spec/checkout_sdk/payments/contexts/contexts_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,40 @@ def create_payment_contexts_paypal
response
end

def create_payment_contexts_klarna
request = {
'source' => {
'type' => 'klarna',
'account_holder' => {
'billing_address' => {
'country' => 'DE'
}
}
},
'amount' => 1000,
'currency' => CheckoutSdk::Common::Currency::EUR,
'payment_type' => CheckoutSdk::Payments::PaymentType::REGULAR,
'processing_channel_id' => ENV.fetch('CHECKOUT_PROCESSING_CHANNEL_ID', nil),
'items' => [
{
'name' => 'mask',
'unit_price' => 1000,
'quantity' => 1,
'total_amount' => 1000,
'reference' => 'BA67A'
}
],
'processing' => {
'locale' => 'en-GB'
}
}

response = default_sdk.contexts.create_payment_contexts(request)
expect(response).not_to be nil
expect(response.id).not_to be nil
expect(response.partner_metadata.client_token).not_to be nil
expect(response.partner_metadata.session_id).not_to be nil
response
end

end
35 changes: 3 additions & 32 deletions spec/checkout_sdk/payments/contexts/contexts_integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,15 @@

before(:all) do
@payment_context_paypal = create_payment_contexts_paypal
@payment_context_klarna = create_payment_contexts_klarna
end

describe '.create_payment_contexts' do
context 'when creating a payment contexts paypal with valid data' do
it { is_valid_payment_context @payment_context_paypal }
end
context 'when creating a payment contexts klarna with valid data' do
it 'raises an error (apm_service_unavailable)' do
request = {
'source' => {
'type' => 'klarna',
'account_holder' => {
'billing_address' => {
'country' => 'DE'
}
}
},
'amount' => 1000,
'currency' => CheckoutSdk::Common::Currency::EUR,
'payment_type' => CheckoutSdk::Payments::PaymentType::REGULAR,
'processing_channel_id' => ENV.fetch('CHECKOUT_PROCESSING_CHANNEL_ID', nil),
'items' => [
{
'name' => 'mask',
'unit_price' => 1000,
'quantity' => 1,
'total_amount' => 1000,
'reference' => 'BA67A'
}
],
'processing' => {
'locale' => 'en-GB'
}
}
expect { default_sdk.contexts.create_payment_contexts(request) }
.to raise_error(CheckoutSdk::CheckoutApiException) { |e| expect(e.error_details[:error_codes].first).to eq 'apm_service_unavailable' }
end
it { is_valid_payment_context @payment_context_klarna }
end
end

Expand All @@ -54,8 +26,7 @@

def is_valid_payment_context(payment_context)
assert_response payment_context, %w[id
partner_metadata
partner_metadata.order_id]
partner_metadata]
end

def is_valid_payment_context_details(payment_context_details_response)
Expand Down

0 comments on commit ef64c60

Please sign in to comment.