Skip to content

Commit d2445b6

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 afa51dc commit d2445b6

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
@@ -452,9 +452,15 @@
452452

453453

454454
describe '#call_adyen_api' do
455+
let(:client) { Adyen::Client.new(api_key: 'test_key', env: :test) }
456+
let(:mock_faraday_connection) { double(Faraday::Connection) }
457+
458+
before do
459+
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
460+
allow(mock_faraday_connection).to receive(:adapter)
461+
end
462+
455463
it 'successfully makes a POST request and returns AdyenResult' do
456-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
457-
mock_faraday_connection = double(Faraday::Connection)
458464
response_body = { pspReference: '123456789', resultCode: 'Authorised' }.to_json
459465
mock_response = Faraday::Response.new(
460466
status: 200,
@@ -465,7 +471,6 @@
465471
expect(Faraday).to receive(:new)
466472
.with('https://checkout-test.adyen.com/v71/payments', anything)
467473
.and_return(mock_faraday_connection)
468-
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
469474
allow(mock_faraday_connection).to receive(:post).and_return(mock_response)
470475

471476
result = client.call_adyen_api('Checkout', 'payments', { amount: { value: 1000 } }, {}, '71')
@@ -476,77 +481,67 @@
476481
end
477482

478483
it 'successfully makes a GET request' do
479-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
480-
mock_faraday_connection = double(Faraday::Connection)
481484
response_body = { data: [{ id: '1' }] }.to_json
482485
mock_response = Faraday::Response.new(status: 200, body: response_body, response_headers: {})
483486

484487
expect(Faraday).to receive(:new)
485-
.with('https://management-test.adyen.com/v1/companies', anything)
488+
.with('https://management-test.adyen.com/v1/merchants/MyMerchantID/paymentsApps', anything)
486489
.and_return(mock_faraday_connection)
487490
.and_yield(mock_faraday_connection)
488-
allow(mock_faraday_connection).to receive(:adapter)
489-
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
490491
allow(mock_faraday_connection).to receive(:get).and_return(mock_response)
491492

492-
result = client.call_adyen_api('Management', { url: 'companies', method: 'get' }, {}, {}, '1')
493+
result = client.call_adyen_api(
494+
'Management',
495+
{ url: 'merchants/MyMerchantID/paymentsApps', method: 'get' },
496+
{},
497+
{},
498+
'1'
499+
)
493500

494501
expect(result).to be_a(Adyen::AdyenResult)
495502
expect(result.status).to eq(200)
496503
end
497504

498505
it 'sets correct headers including custom headers' do
499-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
500-
mock_faraday_connection = double(Faraday::Connection)
501506
mock_response = Faraday::Response.new(status: 200, body: '{}', response_headers: {})
502-
503507
headers_spy = {}
508+
504509
expect(Faraday).to receive(:new)
505-
.with('https://checkout-test.adyen.com/v71/payments', anything)
510+
.with('https://checkout-test.adyen.com/v71/storedPaymentMethods', anything)
506511
.and_return(mock_faraday_connection)
507512
.and_yield(mock_faraday_connection)
508-
allow(mock_faraday_connection).to receive(:adapter)
509513
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=) do |key, value|
510514
headers_spy[key] = value
511515
end
512516
allow(mock_faraday_connection).to receive(:post).and_return(mock_response)
513517

514518
custom_headers = { 'Idempotency-Key' => 'test-123' }
515-
client.call_adyen_api('Checkout', 'payments', {}, custom_headers, '71')
519+
client.call_adyen_api('Checkout', 'storedPaymentMethods', {}, custom_headers, '71')
516520

517521
expect(headers_spy['Content-Type']).to eq('application/json')
518522
expect(headers_spy['x-api-key']).to eq('test_key')
519523
expect(headers_spy['Idempotency-Key']).to eq('test-123')
520524
end
521525

522526
it 'handles connection failures' do
523-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
524-
mock_faraday_connection = double(Faraday::Connection)
525-
526527
expect(Faraday).to receive(:new)
527-
.with('https://checkout-test.adyen.com/v71/payments', anything)
528+
.with('https://checkout-test.adyen.com/v71/paymentLinks/PL61C53A8B97E6924D', anything)
528529
.and_return(mock_faraday_connection)
529530
.and_yield(mock_faraday_connection)
530-
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
531-
allow(mock_faraday_connection).to receive(:adapter)
532531
allow(mock_faraday_connection).to receive(:post).and_raise(Faraday::ConnectionFailed.new('Connection failed'))
533532

534533
expect {
535-
client.call_adyen_api('Checkout', 'payments', {}, {}, '71')
534+
client.call_adyen_api('Checkout', 'paymentLinks/PL61C53A8B97E6924D', {}, {}, '71')
536535
}.to raise_error(Faraday::ConnectionFailed, /Connection to .* failed/)
537536
end
538537

539538
it 'converts request data to JSON' do
540-
client = Adyen::Client.new(api_key: 'test_key', env: :test)
541-
mock_faraday_connection = double(Faraday::Connection)
542539
mock_response = Faraday::Response.new(status: 200, body: '{}', response_headers: {})
543540

544541
expect(Faraday).to receive(:new)
545542
.with('https://checkout-test.adyen.com/v71/payments', anything)
546543
.and_return(mock_faraday_connection)
547544
.and_yield(mock_faraday_connection)
548-
allow(mock_faraday_connection).to receive(:adapter)
549-
allow(mock_faraday_connection).to receive_message_chain(:headers, :[]=)
550545

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

0 commit comments

Comments
 (0)