Skip to content

Commit a071925

Browse files
committed
Introduce Client#call_adyen_api_url method
This method allows passing in a full URL for users that do not want to use the whole concept of services and actions.
1 parent b08262d commit a071925

File tree

2 files changed

+182
-71
lines changed

2 files changed

+182
-71
lines changed

lib/adyen/client.rb

Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,19 @@ def service_url(service, action, version)
144144
def call_adyen_api(service, action, request_data, headers, version, _with_application_info: false)
145145
# get URL for requested endpoint
146146
url = service_url(service, action.is_a?(String) ? action : action.fetch(:url), version)
147-
148-
auth_type = auth_type(service, request_data)
147+
148+
# make sure valid authentication has been provided
149+
validate_auth_type(service, request_data)
150+
151+
method = action.is_a?(String) ? 'post' : action.fetch(:method)
152+
153+
call_adyen_api_url(url, method, request_data, headers)
154+
end
155+
156+
# send request to adyen API with a given full URL
157+
def call_adyen_api_url(url, method, request_data, headers)
158+
# make sure valid authentication has been provided, without a specific service
159+
validate_auth_type(nil, request_data)
149160

150161
# initialize Faraday connection object
151162
conn = Faraday.new(url, @connection_options) do |faraday|
@@ -154,7 +165,7 @@ def call_adyen_api(service, action, request_data, headers, version, _with_applic
154165
faraday.headers['User-Agent'] = "#{Adyen::NAME}/#{Adyen::VERSION}"
155166

156167
# set header based on auth_type and service
157-
auth_header(auth_type, faraday)
168+
add_auth_header(faraday)
158169

159170
# add optional headers if specified in request
160171
# will overwrite default headers if overlapping
@@ -173,49 +184,27 @@ def call_adyen_api(service, action, request_data, headers, version, _with_applic
173184
# convert to json
174185
request_data = request_data.to_json
175186

176-
if action.is_a?(::Hash)
177-
if action.fetch(:method) == 'get'
178-
begin
179-
response = conn.get
180-
rescue Faraday::ConnectionFailed => e
181-
raise e, "Connection to #{url} failed"
182-
end
183-
end
184-
if action.fetch(:method) == 'delete'
185-
begin
186-
response = conn.delete
187-
rescue Faraday::ConnectionFailed => e
188-
raise e, "Connection to #{url} failed"
189-
end
190-
end
191-
if action.fetch(:method) == 'patch'
192-
begin
193-
response = conn.patch do |req|
187+
begin
188+
response = case method
189+
when 'get'
190+
conn.get
191+
when 'delete'
192+
conn.delete
193+
when 'patch'
194+
conn.patch do |req|
194195
req.body = request_data
195196
end
196-
rescue Faraday::ConnectionFailed => e
197-
raise e, "Connection to #{url} failed"
198-
end
199-
end
200-
if action.fetch(:method) == 'post'
201-
# post request to Adyen
202-
begin
203-
response = conn.post do |req|
197+
when 'post'
198+
conn.post do |req|
204199
req.body = request_data
205200
end
206-
rescue Faraday::ConnectionFailed => e
207-
raise e, "Connection to #{url} failed"
208-
end
209-
end
210-
else
211-
begin
212-
response = conn.post do |req|
213-
req.body = request_data
201+
else
202+
raise ArgumentError, "Invalid HTTP method: #{method}"
214203
end
215-
rescue Faraday::ConnectionFailed => e
216-
raise e, "Connection to #{url} failed"
217-
end
204+
rescue Faraday::ConnectionFailed => e
205+
raise e, "Connection to #{url} failed"
218206
end
207+
219208
# check for API errors
220209
case response.status
221210
when 400
@@ -326,10 +315,10 @@ def balance_control
326315
@balance_control ||= Adyen::BalanceControl.new(self)
327316
end
328317

329-
318+
330319
private
331320

332-
def auth_header(auth_type, faraday)
321+
def add_auth_header(faraday)
333322
case auth_type
334323
when "basic"
335324
if Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('2.0')
@@ -346,9 +335,7 @@ def auth_header(auth_type, faraday)
346335
end
347336
end
348337

349-
def auth_type(service, request_data)
350-
# make sure valid authentication has been provided
351-
validate_auth_type(service, request_data)
338+
def auth_type
352339
# Will prioritize authentication methods in this order:
353340
# api-key, oauth, basic
354341
return "api-key" unless @api_key.nil?

spec/client_spec.rb

Lines changed: 150 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,15 @@
433433
end
434434

435435
describe '#call_adyen_api' do
436+
let(:client) { Adyen::Client.new(api_key: 'test_key', env: :test) }
437+
let(:mock_faraday_connection) { double(Faraday::Connection) }
438+
439+
before do
440+
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
441+
allow(mock_faraday_connection).to receive(:adapter)
442+
end
443+
436444
it 'successfully makes a POST request and returns AdyenResult' do
437-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
438-
mock_faraday_connection = double(Faraday::Connection)
439445
response_body = { pspReference: '123456789', resultCode: 'Authorised' }.to_json
440446
mock_response = Faraday::Response.new(
441447
status: 200,
@@ -446,7 +452,6 @@
446452
expect(Faraday).to receive(:new)
447453
.with('https://checkout-test.adyen.com/v71/payments', anything)
448454
.and_return(mock_faraday_connection)
449-
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
450455
allow(mock_faraday_connection).to receive(:post).and_return(mock_response)
451456

452457
result = client.call_adyen_api('Checkout', 'payments', { amount: { value: 1000 } }, {}, '71')
@@ -457,77 +462,67 @@
457462
end
458463

459464
it 'successfully makes a GET request' do
460-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
461-
mock_faraday_connection = double(Faraday::Connection)
462465
response_body = { data: [{ id: '1' }] }.to_json
463466
mock_response = Faraday::Response.new(status: 200, body: response_body, response_headers: {})
464467

465468
expect(Faraday).to receive(:new)
466-
.with('https://management-test.adyen.com/v1/companies', anything)
469+
.with('https://management-test.adyen.com/v1/merchants/MyMerchantID/paymentsApps', anything)
467470
.and_return(mock_faraday_connection)
468471
.and_yield(mock_faraday_connection)
469-
allow(mock_faraday_connection).to receive(:adapter)
470-
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
471472
allow(mock_faraday_connection).to receive(:get).and_return(mock_response)
472473

473-
result = client.call_adyen_api('Management', { url: 'companies', method: 'get' }, {}, {}, '1')
474+
result = client.call_adyen_api(
475+
'Management',
476+
{ url: 'merchants/MyMerchantID/paymentsApps', method: 'get' },
477+
{},
478+
{},
479+
'1'
480+
)
474481

475482
expect(result).to be_a(Adyen::AdyenResult)
476483
expect(result.status).to eq(200)
477484
end
478485

479486
it 'sets correct headers including custom headers' do
480-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
481-
mock_faraday_connection = double(Faraday::Connection)
482487
mock_response = Faraday::Response.new(status: 200, body: '{}', response_headers: {})
483-
484488
headers_spy = {}
489+
485490
expect(Faraday).to receive(:new)
486-
.with('https://checkout-test.adyen.com/v71/payments', anything)
491+
.with('https://checkout-test.adyen.com/v71/storedPaymentMethods', anything)
487492
.and_return(mock_faraday_connection)
488493
.and_yield(mock_faraday_connection)
489-
allow(mock_faraday_connection).to receive(:adapter)
490494
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=) do |key, value|
491495
headers_spy[key] = value
492496
end
493497
allow(mock_faraday_connection).to receive(:post).and_return(mock_response)
494498

495499
custom_headers = { 'Idempotency-Key' => 'test-123' }
496-
client.call_adyen_api('Checkout', 'payments', {}, custom_headers, '71')
500+
client.call_adyen_api('Checkout', 'storedPaymentMethods', {}, custom_headers, '71')
497501

498502
expect(headers_spy['Content-Type']).to eq('application/json')
499503
expect(headers_spy['x-api-key']).to eq('test_key')
500504
expect(headers_spy['Idempotency-Key']).to eq('test-123')
501505
end
502506

503507
it 'handles connection failures' do
504-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
505-
mock_faraday_connection = double(Faraday::Connection)
506-
507508
expect(Faraday).to receive(:new)
508-
.with('https://checkout-test.adyen.com/v71/payments', anything)
509+
.with('https://checkout-test.adyen.com/v71/paymentLinks/PL61C53A8B97E6924D', anything)
509510
.and_return(mock_faraday_connection)
510511
.and_yield(mock_faraday_connection)
511-
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
512-
allow(mock_faraday_connection).to receive(:adapter)
513512
allow(mock_faraday_connection).to receive(:post).and_raise(Faraday::ConnectionFailed.new('Connection failed'))
514513

515514
expect {
516-
client.call_adyen_api('Checkout', 'payments', {}, {}, '71')
515+
client.call_adyen_api('Checkout', 'paymentLinks/PL61C53A8B97E6924D', {}, {}, '71')
517516
}.to raise_error(Faraday::ConnectionFailed, /Connection to .* failed/)
518517
end
519518

520519
it 'converts request data to JSON' do
521-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
522-
mock_faraday_connection = double(Faraday::Connection)
523520
mock_response = Faraday::Response.new(status: 200, body: '{}', response_headers: {})
524521

525522
expect(Faraday).to receive(:new)
526523
.with('https://checkout-test.adyen.com/v71/payments', anything)
527524
.and_return(mock_faraday_connection)
528525
.and_yield(mock_faraday_connection)
529-
allow(mock_faraday_connection).to receive(:adapter)
530-
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
531526

532527
request_body_sent = nil
533528
allow(mock_faraday_connection).to receive(:post) do |&block|
@@ -543,4 +538,133 @@
543538
expect(request_body_sent).to eq(hash_data.to_json)
544539
end
545540
end
541+
542+
describe '#call_adyen_api_url' do
543+
let(:client) { Adyen::Client.new(api_key: 'test_key', env: :test) }
544+
let(:mock_faraday_connection) { double(Faraday::Connection) }
545+
546+
before do
547+
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
548+
allow(mock_faraday_connection).to receive(:adapter)
549+
end
550+
551+
it 'successfully makes a POST request with full URL' do
552+
response_body = { pspReference: '987654321', resultCode: 'Authorised' }.to_json
553+
mock_response = Faraday::Response.new(
554+
status: 200,
555+
body: response_body,
556+
response_headers: { 'content-type' => 'application/json' }
557+
)
558+
559+
expect(Faraday).to receive(:new)
560+
.with('https://balanceplatform-api-test.adyen.com/capital/v1/grants', anything)
561+
.and_return(mock_faraday_connection)
562+
.and_yield(mock_faraday_connection)
563+
allow(mock_faraday_connection).to receive(:post).and_return(mock_response)
564+
565+
result = client.call_adyen_api_url(
566+
'https://balanceplatform-api-test.adyen.com/capital/v1/grants',
567+
'post',
568+
{ amount: { value: 2000 } },
569+
{}
570+
)
571+
572+
expect(result).to be_a(Adyen::AdyenResult)
573+
expect(result.status).to eq(200)
574+
expect(result.response["pspReference"]).to eq('987654321')
575+
end
576+
577+
it 'successfully makes a GET request' do
578+
response_body = { data: [{ id: 'comp-1' }] }.to_json
579+
mock_response = Faraday::Response.new(status: 200, body: response_body, response_headers: {})
580+
581+
expect(Faraday).to receive(:new)
582+
.with('https://management-test.adyen.com/v3/merchants/MyMerchantID/stores', anything)
583+
.and_return(mock_faraday_connection)
584+
.and_yield(mock_faraday_connection)
585+
allow(mock_faraday_connection).to receive(:get).and_return(mock_response)
586+
587+
result = client.call_adyen_api_url(
588+
'https://management-test.adyen.com/v3/merchants/MyMerchantID/stores',
589+
'get',
590+
{},
591+
{}
592+
)
593+
594+
expect(result).to be_a(Adyen::AdyenResult)
595+
expect(result.status).to eq(200)
596+
end
597+
598+
it 'sets correct headers' do
599+
mock_response = Faraday::Response.new(status: 200, body: '{}', response_headers: {})
600+
headers_spy = {}
601+
602+
expect(Faraday).to receive(:new)
603+
.with('https://custom.adyen.com/api/endpoint', anything)
604+
.and_return(mock_faraday_connection)
605+
.and_yield(mock_faraday_connection)
606+
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=) do |key, value|
607+
headers_spy[key] = value
608+
end
609+
allow(mock_faraday_connection).to receive(:post).and_return(mock_response)
610+
611+
custom_headers = { 'X-Custom-Header' => 'custom-value' }
612+
client.call_adyen_api_url('https://custom.adyen.com/api/endpoint', 'post', {}, custom_headers)
613+
614+
expect(headers_spy['Content-Type']).to eq('application/json')
615+
expect(headers_spy['x-api-key']).to eq('test_key')
616+
expect(headers_spy['X-Custom-Header']).to eq('custom-value')
617+
end
618+
619+
it 'handles connection failures' do
620+
expect(Faraday).to receive(:new)
621+
.with('https://management-test.adyen.com/v3/stores', anything)
622+
.and_return(mock_faraday_connection)
623+
.and_yield(mock_faraday_connection)
624+
allow(mock_faraday_connection).to receive(:post).and_raise(Faraday::ConnectionFailed.new('Connection failed'))
625+
626+
expect {
627+
client.call_adyen_api_url('https://management-test.adyen.com/v3/stores', 'post', {}, {})
628+
}.to raise_error(Faraday::ConnectionFailed, /Connection to .* failed/)
629+
end
630+
631+
it 'supports different HTTP methods' do
632+
mock_response = Faraday::Response.new(status: 200, body: '{"status":"updated"}', response_headers: {})
633+
634+
expect(Faraday).to receive(:new)
635+
.with('https://checkout-test.adyen.com/v71/paymentLinks/PL61C53A8B97E6915A', anything)
636+
.and_return(mock_faraday_connection)
637+
.and_yield(mock_faraday_connection)
638+
allow(mock_faraday_connection).to receive(:patch).and_return(mock_response)
639+
640+
result = client.call_adyen_api_url(
641+
'https://checkout-test.adyen.com/v71/paymentLinks/PL61C53A8B97E6915A',
642+
'patch',
643+
{ status: 'active' },
644+
{}
645+
)
646+
647+
expect(result).to be_a(Adyen::AdyenResult)
648+
expect(result.status).to eq(200)
649+
end
650+
651+
it 'raises for invalid HTTP method' do
652+
expect {
653+
client.call_adyen_api_url('https://management-test.adyen.com/v1/something', 'invalid', {}, {})
654+
}.to raise_error(ArgumentError, "Invalid HTTP method: invalid")
655+
end
656+
657+
it 'validates authentication is provided' do
658+
client_without_auth = Adyen::Client.new(env: :test)
659+
660+
expect {
661+
client_without_auth.call_adyen_api_url(
662+
'https://checkout-test.adyen.com/v71/paymentMethods/balance',
663+
'post',
664+
{},
665+
{}
666+
)
667+
}.to raise_error(Adyen::AuthenticationError, /No authentication found/)
668+
end
669+
end
546670
end

0 commit comments

Comments
 (0)