Skip to content

Commit 6d44071

Browse files
committed
Fix issue in underlying API request
1 parent 65b36b9 commit 6d44071

8 files changed

Lines changed: 431 additions & 239 deletions

File tree

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
loops_sdk (1.1.0)
4+
loops_sdk (1.2.0)
55
faraday
66

77
GEM

lib/loops_sdk/base.rb

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,15 @@ def handle_response(response)
2121
end
2222

2323
def make_request(method:, path:, headers: {}, params: {}, body: nil)
24-
# Merge default headers with request-specific headers
2524
merged_headers = LoopsSdk.configuration.connection.headers.merge(headers)
26-
27-
response = LoopsSdk.configuration.connection.send(
28-
method: method,
29-
path: path,
30-
headers: merged_headers,
31-
params: params,
32-
body: body
33-
) do |req|
34-
req.body = body.to_json if body
35-
req
25+
26+
response = LoopsSdk.configuration.connection.send(method) do |req|
27+
req.url path
28+
req.headers = merged_headers
29+
req.params = params
30+
req.body = body ? body.to_json : nil
3631
end
32+
3733
handle_response(response)
3834
end
3935
end

lib/loops_sdk/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module LoopsSdk
4-
VERSION = "1.2.0"
4+
VERSION = "1.2.1"
55
end

spec/examples.txt

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
example_id | status | run_time |
22
--------------------------------------------- | ------ | --------------- |
3-
./spec/loops_sdk/base_spec.rb[1:1:1:1] | passed | 0.00118 seconds |
4-
./spec/loops_sdk/base_spec.rb[1:1:1:2] | passed | 0.00178 seconds |
5-
./spec/loops_sdk/base_spec.rb[1:1:2:1] | passed | 0.0007 seconds |
6-
./spec/loops_sdk/base_spec.rb[1:1:3:1] | passed | 0.00253 seconds |
7-
./spec/loops_sdk/base_spec.rb[1:2:1:1] | passed | 0.00014 seconds |
8-
./spec/loops_sdk/base_spec.rb[1:2:2:1] | passed | 0.00012 seconds |
3+
./spec/loops_sdk/base_spec.rb[1:1:1] | passed | 0.00218 seconds |
4+
./spec/loops_sdk/base_spec.rb[1:1:2] | passed | 0.00044 seconds |
5+
./spec/loops_sdk/base_spec.rb[1:1:3] | passed | 0.00043 seconds |
6+
./spec/loops_sdk/base_spec.rb[1:1:4] | passed | 0.00198 seconds |
7+
./spec/loops_sdk/base_spec.rb[1:1:5] | passed | 0.00061 seconds |
8+
./spec/loops_sdk/base_spec.rb[1:1:6] | passed | 0.00045 seconds |
9+
./spec/loops_sdk/base_spec.rb[1:2:1:1] | passed | 0.00017 seconds |
10+
./spec/loops_sdk/base_spec.rb[1:2:2:1] | passed | 0.00016 seconds |
911
./spec/loops_sdk/base_spec.rb[1:2:2:2] | passed | 0.00014 seconds |
10-
./spec/loops_sdk/events_spec.rb[1:1:1] | passed | 0.00039 seconds |
11-
./spec/loops_sdk/events_spec.rb[1:1:2] | passed | 0.00096 seconds |
12-
./spec/loops_sdk/events_spec.rb[1:1:3] | passed | 0.00033 seconds |
13-
./spec/loops_sdk/events_spec.rb[1:1:4] | passed | 0.00031 seconds |
14-
./spec/loops_sdk/events_spec.rb[1:1:5] | passed | 0.00034 seconds |
15-
./spec/loops_sdk/events_spec.rb[1:1:6] | passed | 0.00192 seconds |
16-
./spec/loops_sdk/transactional_spec.rb[1:1:1] | passed | 0.00259 seconds |
17-
./spec/loops_sdk/transactional_spec.rb[1:1:2] | passed | 0.00032 seconds |
18-
./spec/loops_sdk/transactional_spec.rb[1:2:1] | passed | 0.00368 seconds |
19-
./spec/loops_sdk/transactional_spec.rb[1:2:2] | passed | 0.00033 seconds |
20-
./spec/loops_sdk/transactional_spec.rb[1:2:3] | passed | 0.00074 seconds |
21-
./spec/loops_sdk/transactional_spec.rb[1:2:4] | passed | 0.00036 seconds |
22-
./spec/loops_sdk/transactional_spec.rb[1:2:5] | passed | 0.00036 seconds |
12+
./spec/loops_sdk/contacts_spec.rb[1:1:1:1] | passed | 0.00294 seconds |
13+
./spec/loops_sdk/contacts_spec.rb[1:1:1:2] | passed | 0.00076 seconds |
14+
./spec/loops_sdk/contacts_spec.rb[1:1:2:1] | passed | 0.00076 seconds |
15+
./spec/loops_sdk/contacts_spec.rb[1:1:3:1] | passed | 0.00537 seconds |
16+
./spec/loops_sdk/contacts_spec.rb[1:1:3:2] | passed | 0.00035 seconds |
17+
./spec/loops_sdk/contacts_spec.rb[1:1:4:1] | passed | 0.00071 seconds |
18+
./spec/loops_sdk/events_spec.rb[1:1:1] | passed | 0.00067 seconds |
19+
./spec/loops_sdk/events_spec.rb[1:1:2] | passed | 0.00044 seconds |
20+
./spec/loops_sdk/events_spec.rb[1:1:3] | passed | 0.00065 seconds |
21+
./spec/loops_sdk/events_spec.rb[1:1:4] | passed | 0.00048 seconds |
22+
./spec/loops_sdk/events_spec.rb[1:1:5] | passed | 0.00046 seconds |
23+
./spec/loops_sdk/events_spec.rb[1:1:6] | passed | 0.00018 seconds |
24+
./spec/loops_sdk/transactional_spec.rb[1:1:1] | passed | 0.00045 seconds |
25+
./spec/loops_sdk/transactional_spec.rb[1:1:2] | passed | 0.00071 seconds |
26+
./spec/loops_sdk/transactional_spec.rb[1:2:1] | passed | 0.00151 seconds |
27+
./spec/loops_sdk/transactional_spec.rb[1:2:2] | passed | 0.00064 seconds |
28+
./spec/loops_sdk/transactional_spec.rb[1:2:3] | passed | 0.00232 seconds |
29+
./spec/loops_sdk/transactional_spec.rb[1:2:4] | passed | 0.00196 seconds |
30+
./spec/loops_sdk/transactional_spec.rb[1:2:5] | passed | 0.00071 seconds |

spec/loops_sdk/base_spec.rb

Lines changed: 118 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -15,102 +15,137 @@
1515
before do
1616
allow(LoopsSdk.configuration).to receive(:connection).and_return(connection)
1717
allow(connection).to receive(:headers).and_return(default_headers)
18+
# Make make_request public for testing
19+
described_class.class_eval { public_class_method :make_request }
1820
end
1921

2022
describe ".make_request" do
21-
let(:params) { { key: "value" } }
22-
let(:body) { { data: "test" } }
23-
24-
context "with successful response" do
25-
it "makes a successful request and parses JSON response" do
26-
expect(connection).to receive(:send).with(
27-
method: :get,
28-
path: "/test",
29-
headers: default_headers,
30-
params: params,
31-
body: nil
32-
) do |**_kwargs, &block|
33-
req = double("req")
34-
block.call(req)
35-
response
36-
end
37-
allow(response).to receive(:status).and_return(200)
38-
allow(response).to receive(:body).and_return('{"data":"test"}')
39-
result = described_class.send(:make_request, method: :get, path: "/test", params: params)
40-
expect(result).to eq({ "data" => "test" })
23+
let(:path) { "v1/test" }
24+
let(:method) { :get }
25+
let(:params) { { foo: "bar" } }
26+
let(:body) { { baz: "qux" } }
27+
let(:headers) { { "Custom-Header" => "value" } }
28+
let(:merged_headers) { default_headers.merge(headers) }
29+
30+
it "makes a successful GET request" do
31+
expect(connection).to receive(:send).with(:get) do |&block|
32+
req = double("req")
33+
expect(req).to receive(:url).with(path)
34+
expect(req).to receive(:headers=).with(default_headers)
35+
expect(req).to receive(:params=).with(params)
36+
expect(req).to receive(:body=).with(nil)
37+
block.call(req)
38+
response
4139
end
4240

43-
it "includes body in request when provided" do
44-
expect(connection).to receive(:send).with(
45-
method: :post,
46-
path: "/test",
47-
headers: default_headers,
48-
params: {},
49-
body: body
50-
) do |**_kwargs, &block|
51-
req = double("req")
52-
expect(req).to receive(:body=) do |request_body|
53-
expect(JSON.parse(request_body)).to eq(JSON.parse(body.to_json))
54-
end
55-
block.call(req)
56-
response
41+
allow(response).to receive(:status).and_return(200)
42+
allow(response).to receive(:body).and_return('{"success":true}')
43+
44+
result = described_class.make_request(method: method, path: path, params: params)
45+
expect(result).to eq({ "success" => true })
46+
end
47+
48+
it "includes body in POST request" do
49+
expect(connection).to receive(:send).with(:post) do |&block|
50+
req = double("req")
51+
expect(req).to receive(:url).with(path)
52+
expect(req).to receive(:headers=).with(default_headers)
53+
expect(req).to receive(:params=).with({})
54+
expect(req).to receive(:body=) do |body|
55+
expect(JSON.parse(body)).to eq(JSON.parse({ baz: "qux" }.to_json))
5756
end
58-
allow(response).to receive(:status).and_return(200)
59-
allow(response).to receive(:body).and_return('{"success":true}')
60-
result = described_class.send(:make_request, method: :post, path: "/test", body: body)
61-
expect(result).to eq({ "success" => true })
57+
block.call(req)
58+
response
6259
end
60+
61+
allow(response).to receive(:status).and_return(200)
62+
allow(response).to receive(:body).and_return('{"success":true}')
63+
64+
result = described_class.make_request(method: :post, path: path, body: body)
65+
expect(result).to eq({ "success" => true })
6366
end
6467

65-
context "with rate limit error" do
66-
it "raises RateLimitError" do
67-
expect(connection).to receive(:send).with(
68-
method: :get,
69-
path: "/test",
70-
headers: default_headers,
71-
params: params,
72-
body: nil
73-
) do |**_kwargs, &block|
74-
req = double("req")
75-
block.call(req)
76-
response
77-
end
78-
allow(response).to receive(:status).and_return(429)
79-
allow(response).to receive(:headers).and_return(
80-
"x-ratelimit-limit" => "100",
81-
"x-ratelimit-remaining" => "0"
82-
)
83-
expect {
84-
described_class.send(:make_request, method: :get, path: "/test", params: params)
85-
}.to raise_error(LoopsSdk::RateLimitError) do |error|
86-
expect(error.limit).to eq("100")
87-
expect(error.remaining).to eq("0")
88-
end
68+
it "includes custom headers merged with default headers" do
69+
expect(connection).to receive(:send).with(:get) do |&block|
70+
req = double("req")
71+
expect(req).to receive(:url).with(path)
72+
expect(req).to receive(:headers=).with(merged_headers)
73+
expect(req).to receive(:params=).with({})
74+
expect(req).to receive(:body=).with(nil)
75+
block.call(req)
76+
response
8977
end
78+
79+
allow(response).to receive(:status).and_return(200)
80+
allow(response).to receive(:body).and_return('{"success":true}')
81+
82+
result = described_class.make_request(method: method, path: path, headers: headers)
83+
expect(result).to eq({ "success" => true })
9084
end
9185

92-
context "with API error" do
93-
it "raises APIError with status and message" do
94-
expect(connection).to receive(:send).with(
95-
method: :get,
96-
path: "/test",
97-
headers: default_headers,
98-
params: params,
99-
body: nil
100-
) do |**_kwargs, &block|
101-
req = double("req")
102-
block.call(req)
103-
response
104-
end
105-
allow(response).to receive(:status).and_return(400)
106-
allow(response).to receive(:body).and_return('{"message":"Bad Request"}')
107-
expect {
108-
described_class.send(:make_request, method: :get, path: "/test", params: params)
109-
}.to raise_error(LoopsSdk::APIError) do |error|
110-
expect(error.statusCode).to eq(400)
111-
expect(error.json).to eq('{"message":"Bad Request"}')
112-
end
86+
it "allows custom headers to override default headers" do
87+
custom_content_type = "application/xml"
88+
custom_headers = { "Content-Type" => custom_content_type }
89+
expected_headers = default_headers.merge(custom_headers)
90+
91+
expect(connection).to receive(:send).with(:get) do |&block|
92+
req = double("req")
93+
expect(req).to receive(:url).with(path)
94+
expect(req).to receive(:headers=).with(expected_headers)
95+
expect(req).to receive(:params=).with({})
96+
expect(req).to receive(:body=).with(nil)
97+
block.call(req)
98+
response
11399
end
100+
101+
allow(response).to receive(:status).and_return(200)
102+
allow(response).to receive(:body).and_return('{"success":true}')
103+
104+
result = described_class.make_request(method: method, path: path, headers: custom_headers)
105+
expect(result).to eq({ "success" => true })
106+
end
107+
108+
it "raises an error when the API returns an error" do
109+
expect(connection).to receive(:send).with(:get) do |&block|
110+
req = double("req")
111+
expect(req).to receive(:url).with(path)
112+
expect(req).to receive(:headers=).with(default_headers)
113+
expect(req).to receive(:params=).with({})
114+
expect(req).to receive(:body=).with(nil)
115+
block.call(req)
116+
response
117+
end
118+
119+
allow(response).to receive(:status).and_return(400)
120+
allow(response).to receive(:body).and_return('{"error":"Bad Request"}')
121+
allow(response).to receive(:headers).and_return({})
122+
123+
expect {
124+
described_class.make_request(method: method, path: path)
125+
}.to raise_error(LoopsSdk::APIError, "API request failed with status 400")
126+
end
127+
128+
it "raises a rate limit error when the API returns 429" do
129+
expect(connection).to receive(:send).with(:get) do |&block|
130+
req = double("req")
131+
expect(req).to receive(:url).with(path)
132+
expect(req).to receive(:headers=).with(default_headers)
133+
expect(req).to receive(:params=).with({})
134+
expect(req).to receive(:body=).with(nil)
135+
block.call(req)
136+
response
137+
end
138+
139+
allow(response).to receive(:status).and_return(429)
140+
allow(response).to receive(:body).and_return('{"error":"Rate limit exceeded"}')
141+
allow(response).to receive(:headers).and_return({
142+
"x-ratelimit-limit" => "100",
143+
"x-ratelimit-remaining" => "0"
144+
})
145+
146+
expect {
147+
described_class.make_request(method: method, path: path)
148+
}.to raise_error(LoopsSdk::RateLimitError, "Rate limit of 100 requests per second exceeded.")
114149
end
115150
end
116151

0 commit comments

Comments
 (0)