my_api_client 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c810e4644f4b3276f9be5b136b196040081204ffd2c1a4590d35f75f7267f37
4
- data.tar.gz: a20a2ad006d18a8211ab056d760d9454f6883dcd6e4f88fcdcda38f6f9bb524b
3
+ metadata.gz: 53a8927025699ceda8733b59f898f51e947c0ea5ea41c7146548d35e6d76242b
4
+ data.tar.gz: 2f4c3aeb97c42d615bdbf8edcd916ec3a9cc90dbd353b31a2b54825289923470
5
5
  SHA512:
6
- metadata.gz: 3c6a1873fb33961931afccaee071ad8c2f734c1bcf3d29937274eae92cac18727a881edb00cd02890a6e7d566d1e8168b12a5cf8c5b124ef61aff27a960e9a50
7
- data.tar.gz: c78a1a59b9f50c89b4489a23fd6fb501727f4e412b184acf5ae9f8be6fe7d1a93a621f1620bc67a25b20193c7a9f766b9d0fdc9642b0e488d45c3a1eeca6b81a
6
+ metadata.gz: f9c5ed6788547461bd09343dedb00d365636aae3e514e756dffdb6702af3f3572a34f5b3bed9e1b3f26f0f400fbbbf782ea33906efc06e712afc73141c8fe668
7
+ data.tar.gz: 5f6a73e3f65a6b5b11e76513d1f7c882676be79324f30d48b9b2d563e262e1e64b13bf9afaa69e373f067a6881f108c032c6da0cb23e861c08f59154daff38a4
@@ -33,7 +33,7 @@ jobs:
33
33
  persist-credentials: false
34
34
 
35
35
  - name: Set up Ruby ${{ matrix.ruby_version }}
36
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
36
+ uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
37
37
  with:
38
38
  ruby-version: ${{ matrix.ruby_version }}
39
39
  bundler-cache: false
@@ -105,7 +105,7 @@ jobs:
105
105
  persist-credentials: false
106
106
 
107
107
  - name: Set up Ruby ${{ matrix.ruby_version }}
108
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
108
+ uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
109
109
  with:
110
110
  ruby-version: ${{ matrix.ruby_version }}
111
111
  bundler-cache: false
@@ -233,7 +233,7 @@ jobs:
233
233
  persist-credentials: false
234
234
 
235
235
  - name: Set up Ruby
236
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
236
+ uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
237
237
  with:
238
238
  ruby-version: '4.0'
239
239
  bundler-cache: false
@@ -255,7 +255,7 @@ jobs:
255
255
  persist-credentials: false
256
256
 
257
257
  - name: Set up Ruby
258
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
258
+ uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
259
259
  with:
260
260
  ruby-version: '4.0'
261
261
  bundler-cache: false
@@ -296,7 +296,7 @@ jobs:
296
296
  persist-credentials: false
297
297
 
298
298
  - name: Set up Ruby
299
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
299
+ uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
300
300
  with:
301
301
  ruby-version: '4.0'
302
302
  bundler-cache: false
@@ -337,7 +337,7 @@ jobs:
337
337
 
338
338
  - name: Upload coverage to Qlty
339
339
  if: ${{ env.QLTY_COVERAGE_TOKEN != '' && hashFiles('coverage/coverage.json') != '' }}
340
- uses: qltysh/qlty-action/coverage@08a0a862c159eae9b9003081da6663d96efef637 # v2.3.0
340
+ uses: qltysh/qlty-action/coverage@ebcd284bf32e36a030afe15f1e136c7be08b9506 # v2.5.0
341
341
  with:
342
342
  token: ${{ env.QLTY_COVERAGE_TOKEN }}
343
343
  files: coverage/coverage.json
@@ -26,10 +26,16 @@ jobs:
26
26
  ref: ${{ github.ref_name }}
27
27
 
28
28
  - name: Set up Ruby
29
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
29
+ # bundler-cache is disabled to avoid a cache-poisoning attack surface:
30
+ # this workflow publishes a gem, so a poisoned dependency cache could
31
+ # contaminate the released artifact.
32
+ uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
30
33
  with:
31
34
  ruby-version: '4.0'
32
- bundler-cache: true
35
+ bundler-cache: false
36
+
37
+ - name: Install dependencies
38
+ run: bundle install
33
39
 
34
40
  - name: Release gem via Trusted Publishing
35
- uses: rubygems/release-gem@v1
41
+ uses: rubygems/release-gem@7f9650160c1a4e7989fdc9855807bdbd421d8b6b # v1.4.1
@@ -23,7 +23,7 @@ jobs:
23
23
  - uses: actions/checkout@v7 # zizmor: ignore[artipacked]
24
24
 
25
25
  - name: Set up Ruby
26
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
26
+ uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
27
27
  with:
28
28
  ruby-version: '4.0'
29
29
 
data/AGENTS.md CHANGED
@@ -126,7 +126,8 @@
126
126
  ## GitHub Actions Pinning Policy
127
127
 
128
128
  - Pin third-party actions to a full commit SHA with a version comment (e.g. `uses: ruby/setup-ruby@<sha> # v1.321.0`) to satisfy zizmor `unpinned-uses`.
129
- - GitHub-owned actions (`actions/*`, `github/*`, `rubygems/*`, `dependabot/*`) may stay ref-pinned; Dependabot (`github-actions`) keeps the pins and version comments updated.
129
+ - GitHub-owned actions (`actions/*`, `github/*`, `dependabot/*`) may stay ref-pinned; Dependabot (`github-actions`) keeps the pins and version comments updated.
130
+ - Third-party actions outside those GitHub-owned orgs (e.g. `ruby/*`, `rubygems/*`) must be SHA-pinned; zizmor `unpinned-uses` flags them otherwise. Dependabot still keeps the SHA pins and version comments updated.
130
131
 
131
132
  ## Runbook
132
133
 
data/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Change log
2
2
 
3
+ ## v2.2.0 (Oct 25, 2026)
4
+
5
+ ### Feature
6
+
7
+ - [#1405](https://github.com/ryz310/my_api_client/pull/1405) Allow stubbing response headers with the `headers` option when `raise` is an error class ([@okumud](https://github.com/okumud))
8
+ - [#1406](https://github.com/ryz310/my_api_client/pull/1406) Include request duration in success or failure log lines instead of a separate `Duration` line. Update log parsers or alerts that depend on the previous format ([@okumud](https://github.com/okumud))
9
+
10
+ ### Bugfix
11
+
12
+ - [#1405](https://github.com/ryz310/my_api_client/pull/1405) Reject `status_code` and `headers` options alongside an error instance instead of silently ignoring them. Pass an error class when combining these options; specs matching `MyApiClient::Stub::ERROR_MESSAGE` must also account for its updated text ([@okumud](https://github.com/okumud))
13
+
14
+ ### Security
15
+
16
+ - [#1344](https://github.com/ryz310/my_api_client/pull/1344) Disable Bundler caching in the release workflow to prevent cache poisoning ([@ryz310](https://github.com/ryz310))
17
+ - [#1345](https://github.com/ryz310/my_api_client/pull/1345) Pin rubygems/release-gem to a commit SHA ([@ryz310](https://github.com/ryz310))
18
+
19
+ ### Dependabot
20
+
21
+ - [#1392](https://github.com/ryz310/my_api_client/pull/1392) Bump activesupport from 8.1.3.1 to 8.1.4 ([@ryz310](https://github.com/ryz310))
22
+ - [#1371](https://github.com/ryz310/my_api_client/pull/1371) Bump faraday from 2.14.3 to 2.14.4 ([@ryz310](https://github.com/ryz310))
23
+ - [#1396](https://github.com/ryz310/my_api_client/pull/1396) Bump simplecov from 1.0.3 to 1.3.2 ([@ryz310](https://github.com/ryz310))
24
+ - [#1355](https://github.com/ryz310/my_api_client/pull/1355) Bump rubocop-performance from 1.26.1 to 1.27.0 ([@ryz310](https://github.com/ryz310))
25
+ - [#1395](https://github.com/ryz310/my_api_client/pull/1395) Bump rubocop-rspec_rails from 2.32.0 to 2.33.0 ([@ryz310](https://github.com/ryz310))
26
+ - [#1399](https://github.com/ryz310/my_api_client/pull/1399) Bump webmock from 3.26.2 to 3.31.0 ([@ryz310](https://github.com/ryz310))
27
+ - [#1400](https://github.com/ryz310/my_api_client/pull/1400) Bump ruby/setup-ruby from 1.321.0 to 1.334.0 ([@ryz310](https://github.com/ryz310))
28
+ - [#1350](https://github.com/ryz310/my_api_client/pull/1350) Bump rubygems/release-gem from 1.4.0 to 1.4.1 ([@ryz310](https://github.com/ryz310))
29
+ - [#1383](https://github.com/ryz310/my_api_client/pull/1383) Bump qltysh/qlty-action/coverage from 2.3.0 to 2.5.0 ([@ryz310](https://github.com/ryz310))
30
+
31
+ ### Misc
32
+
33
+ - [#1375](https://github.com/ryz310/my_api_client/pull/1375) Clarify API client integration behavior ([@ryz310](https://github.com/ryz310))
34
+
3
35
  ## v2.1.0 (Aug 11, 2026)
4
36
 
5
37
  ### Security
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- my_api_client (2.1.0)
4
+ my_api_client (2.2.0)
5
5
  activesupport (>= 7.2.0)
6
6
  faraday (>= 0.17.1)
7
7
  jsonpath
@@ -10,7 +10,7 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- activesupport (8.1.3.1)
13
+ activesupport (8.1.4)
14
14
  base64
15
15
  bigdecimal
16
16
  concurrent-ruby (~> 1.0, >= 1.3.1)
@@ -27,7 +27,7 @@ GEM
27
27
  public_suffix (>= 2.0.2, < 8.0)
28
28
  ast (2.4.3)
29
29
  base64 (0.3.0)
30
- bigdecimal (4.1.2)
30
+ bigdecimal (4.1.3)
31
31
  bugsnag (6.30.0)
32
32
  concurrent-ruby (~> 1.0)
33
33
  byebug (13.0.0)
@@ -40,7 +40,7 @@ GEM
40
40
  rexml
41
41
  diff-lcs (1.6.2)
42
42
  drb (2.2.3)
43
- faraday (2.14.3)
43
+ faraday (2.14.4)
44
44
  faraday-net_http (>= 2.0, < 3.5)
45
45
  json
46
46
  logger
@@ -63,7 +63,7 @@ GEM
63
63
  multi_json (1.21.1)
64
64
  net-http (0.9.1)
65
65
  uri (>= 0.11.1)
66
- parallel (1.28.0)
66
+ parallel (2.3.0)
67
67
  parser (3.3.12.0)
68
68
  ast (~> 2.4.1)
69
69
  racc
@@ -79,7 +79,7 @@ GEM
79
79
  racc (1.8.1)
80
80
  rainbow (3.1.1)
81
81
  rake (13.4.2)
82
- regexp_parser (2.12.0)
82
+ regexp_parser (2.13.1)
83
83
  reline (0.6.3)
84
84
  io-console (~> 0.5)
85
85
  rexml (3.4.4)
@@ -98,7 +98,7 @@ GEM
98
98
  rspec-support (3.13.7)
99
99
  rspec_junit_formatter (0.6.0)
100
100
  rspec-core (>= 2, < 4, != 2.12.0)
101
- rubocop (1.88.2)
101
+ rubocop (1.89.0)
102
102
  json (~> 2.3)
103
103
  language_server-protocol (~> 3.17.0.2)
104
104
  lint_roller (~> 1.1.0)
@@ -112,9 +112,9 @@ GEM
112
112
  rubocop-ast (1.50.0)
113
113
  parser (>= 3.3.7.2)
114
114
  prism (~> 1.7)
115
- rubocop-performance (1.26.1)
115
+ rubocop-performance (1.27.0)
116
116
  lint_roller (~> 1.1)
117
- rubocop (>= 1.75.0, < 2.0)
117
+ rubocop (>= 1.89.0, < 2.0)
118
118
  rubocop-ast (>= 1.47.1, < 2.0)
119
119
  rubocop-rake (0.7.1)
120
120
  lint_roller (~> 1.1)
@@ -123,23 +123,23 @@ GEM
123
123
  lint_roller (~> 1.1)
124
124
  regexp_parser (>= 2.0)
125
125
  rubocop (~> 1.86, >= 1.86.2)
126
- rubocop-rspec_rails (2.32.0)
126
+ rubocop-rspec_rails (2.33.0)
127
127
  lint_roller (~> 1.1)
128
- rubocop (~> 1.72, >= 1.72.1)
128
+ rubocop (~> 1.89)
129
129
  rubocop-rspec (~> 3.5)
130
130
  ruby-progressbar (1.13.0)
131
131
  sawyer (0.9.3)
132
132
  addressable (>= 2.3.5)
133
133
  faraday (>= 0.17.3, < 3)
134
134
  securerandom (0.4.1)
135
- simplecov (1.0.3)
135
+ simplecov (1.3.2)
136
136
  tzinfo (2.0.6)
137
137
  concurrent-ruby (~> 1.0)
138
- unicode-display_width (3.2.0)
139
- unicode-emoji (~> 4.1)
140
- unicode-emoji (4.2.0)
141
- uri (1.1.1)
142
- webmock (3.26.2)
138
+ unicode-display_width (3.3.0)
139
+ unicode-emoji (~> 4.3)
140
+ unicode-emoji (4.3.0)
141
+ uri (1.1.2)
142
+ webmock (3.31.0)
143
143
  addressable (>= 2.8.0)
144
144
  crack (>= 0.3.2)
145
145
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -161,7 +161,7 @@ DEPENDENCIES
161
161
  rubocop-rake
162
162
  rubocop-rspec
163
163
  rubocop-rspec_rails
164
- simplecov (= 1.0.3)
164
+ simplecov (= 1.3.2)
165
165
  webmock
166
166
  yard
167
167
 
data/README.md CHANGED
@@ -87,8 +87,12 @@ api_client.get_users #=> #<Sawyer::Resource>
87
87
 
88
88
  Next, define `#initialize` to set values such as an access token or API key. You can omit it if you do not need any instance state.
89
89
 
90
+ `MyApiClient::Base` intentionally does not define `#initialize`, so a class that directly inherits from it does not need to call `super()` from its own `#initialize`. If you inherit from another application-specific client class, follow that parent class's initialization contract.
91
+
90
92
  Then define methods such as `#get_users` and `#post_user`. Inside those methods, call HTTP helpers like `#get` and `#post`. You can also use `#patch`, `#put`, and `#delete`.
91
93
 
94
+ Without a block, these HTTP helpers return the response body as a `Sawyer::Resource`. With a block, they yield the full `Sawyer::Response` and return the block's result. See [RSpec](#rspec) for the request and error-handling test helpers provided by this gem.
95
+
92
96
  ### Pagination
93
97
 
94
98
  Some APIs include a URL for the next page in the response.
@@ -260,6 +264,8 @@ Also, `retry_on` is defined by default for `MyApiClient::NetworkError`.
260
264
 
261
265
  Both can be overridden, so define `error_handling` as needed.
262
266
 
267
+ If more than one error handler matches a response, the handler defined last takes precedence. Handlers defined in a subclass are evaluated before inherited handlers, so a subclass can override a built-in handler with a more specific rule.
268
+
263
269
  They are defined [here](https://github.com/ryz310/my_api_client/blob/master/lib/my_api_client/default_error_handlers.rb).
264
270
 
265
271
  #### Use Symbol
@@ -343,6 +349,8 @@ end
343
349
 
344
350
  When an API request is executed many times, network errors can occur. Sometimes the network is unavailable for a long time, but often the error is temporary. In MyApiClient, network-related exceptions are wrapped as `MyApiClient::NetworkError`. Using `retry_on`, you can handle such exceptions and retry requests with configurable wait time and attempt count, similar to `ActiveJob`.
345
351
 
352
+ `attempts` is the number of retries after the initial request, not the total number of requests. For example, `attempts: 0` sends at most one request, while `attempts: 3` sends at most four requests.
353
+
346
354
  `retry_on MyApiClient::NetworkError` is enabled by default, so you do not need to define it unless you want custom `wait` or `attempts` values.
347
355
 
348
356
  Unlike `ActiveJob`, retries are performed synchronously. In practice, this is most useful for short-lived network interruptions. You can also retry for API rate limits as in the example above, but handling that with `ActiveJob` may be a better fit depending on your workload.
@@ -426,8 +434,7 @@ MyApiClient wraps this logger with `MyApiClient::Request::Logger` and prefixes m
426
434
 
427
435
  ```text
428
436
  API request `GET https://example.com/v1/users`: "Start"
429
- API request `GET https://example.com/v1/users`: "Duration 100.0 msec"
430
- API request `GET https://example.com/v1/users`: "Success (200)"
437
+ API request `GET https://example.com/v1/users`: "Success (200) in 100.0 msec"
431
438
  ```
432
439
 
433
440
  On failure, it logs:
@@ -662,7 +669,7 @@ stub_api_client_all(ExampleApiClient, request: { raise: MyApiClient::Error })
662
669
  expect { ExampleApiClient.new.request(user_id: 1) }.to raise_error(MyApiClient::Error)
663
670
  ```
664
671
 
665
- You can combine `raise`, `response`, and `status_code`:
672
+ You can combine `raise`, `response`, `status_code`, and `headers`:
666
673
 
667
674
  ```ruby
668
675
  stub_api_client_all(
@@ -671,17 +678,23 @@ stub_api_client_all(
671
678
  raise: MyApiClient::Error,
672
679
  response: { message: 'error' },
673
680
  status_code: 429,
681
+ headers: { 'Retry-After' => '60' },
674
682
  }
675
683
  )
676
684
 
677
685
  begin
678
686
  ExampleApiClient.new.request(user_id: 1)
679
687
  rescue MyApiClient::Error => e
680
- e.params.response.data.to_h # => { message: "error" }
681
- e.params.response.status # => 429
688
+ e.params.response.data.to_h # => { message: "error" }
689
+ e.params.response.status # => 429
690
+ e.params.response.headers['retry-after'] # => "60"
682
691
  end
683
692
  ```
684
693
 
694
+ Stubbed headers behave like real response headers: names are looked up case-insensitively and values are converted to Strings. Use String keys for header names, because Symbol keys are rewritten (e.g. `:retry_after` becomes `'Retry-After'`).
695
+
696
+ If the `raise` option is an error instance, `response`, `status_code`, and `headers` cannot be combined with it. Pass an error class instead.
697
+
685
698
  #### `pageable` option
686
699
 
687
700
  For `#pageable_get` (`#pget`), you can stub page-by-page responses:
@@ -32,13 +32,13 @@ module MyApiClient
32
32
  def call
33
33
  request_logger.info('Start')
34
34
  response = api_request
35
- request_logger.info("Duration #{response.timing.in_milliseconds} msec")
35
+ duration = " in #{response.timing.in_milliseconds} msec"
36
36
  verify(response)
37
37
  rescue MyApiClient::Error => e
38
- request_logger.warn("Failure (#{e.message})")
38
+ request_logger.warn("Failure (#{e.message})#{duration}")
39
39
  raise
40
40
  else
41
- request_logger.info("Success (#{response.status})")
41
+ request_logger.info("Success (#{response.status})#{duration}")
42
42
  response
43
43
  end
44
44
 
@@ -4,9 +4,9 @@ module MyApiClient
4
4
  # Test helper module for RSpec
5
5
  module Stub
6
6
  ERROR_MESSAGE =
7
- 'If you use the `raise` option as an error instance, the `response` option ' \
8
- 'is ignored. If you want to use both options, you need to specify the ' \
9
- '`raise` option as an error class.'
7
+ 'If you use the `raise` option as an error instance, the `response`, ' \
8
+ '`status_code` and `headers` options are ignored. If you want to use them, ' \
9
+ 'you need to specify the `raise` option as an error class.'
10
10
 
11
11
  # Stubs all instance of arbitrary MyApiClient class.
12
12
  # And returns a stubbed arbitrary MyApiClient instance.
@@ -22,13 +22,14 @@ module MyApiClient
22
22
  # pageable: [ { id: 1 }, { id: 2 }] # for `#pageable_get`.
23
23
  # },
24
24
  # get_user: { response: { id: 1 } }, # Returns an arbitrary response.
25
- # post_users: { id: 1 }, # You can ommit `response` keyword.
25
+ # post_users: { id: 1 }, # You can omit `response` keyword.
26
26
  # patch_user: ->(params) { { id: params[:id] } }, # Returns calculated result as response.
27
27
  # put_user: { raise: MyApiClient::ClientError } # Raises an arbitrary error.
28
28
  # delete_user: {
29
29
  # raise: MyApiClient::ClientError,
30
- # response: { errors: [{ code: 10 }] }, # You can stub response and statu code
30
+ # response: { errors: [{ code: 10 }] }, # You can stub response and status code
31
31
  # status_code: 429, # with an arbitrary error.
32
+ # headers: { 'X-Request-Id' => '123' }, # You can also stub response headers.
32
33
  # }
33
34
  # )
34
35
  # response = ExampleApiClient.new.get_user(id: 123)
@@ -54,13 +55,14 @@ module MyApiClient
54
55
  # pageable: [ { id: 1 }, { id: 2 }] # for `#pageable_get`.
55
56
  # },
56
57
  # get_user: { response: { id: 1 } }, # Returns an arbitrary response.
57
- # post_users: { id: 1 }, # You can ommit `response` keyword.
58
+ # post_users: { id: 1 }, # You can omit `response` keyword.
58
59
  # patch_user: ->(params) { { id: params[:id] } }, # Returns calculated result as response.
59
60
  # put_user: { raise: MyApiClient::ClientError } # Raises an arbitrary error.
60
61
  # delete_user: {
61
62
  # raise: MyApiClient::ClientError,
62
63
  # response: { errors: [{ code: 10 }] }, # You can stub response and status code
63
64
  # status_code: 403, # with exception.
65
+ # headers: { 'X-Request-Id' => '123' }, # You can also stub response headers.
64
66
  # }
65
67
  # )
66
68
  # response = api_client.get_user(id: 123)
@@ -82,13 +84,13 @@ module MyApiClient
82
84
  end
83
85
  end
84
86
 
85
- def generate_stubbed_response(options, *request) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
87
+ def generate_stubbed_response(options, *request) # rubocop:disable Metrics/MethodLength
86
88
  case options
87
89
  when Proc
88
90
  stub_as_resource(options.call(*request))
89
91
  when Hash
90
92
  if options[:raise]
91
- raise process_raise_option(options[:raise], options[:response], options[:status_code])
93
+ raise process_raise_option(options)
92
94
  elsif options[:response]
93
95
  stub_as_resource(options[:response])
94
96
  elsif options[:pageable].is_a?(Enumerable)
@@ -113,37 +115,47 @@ module MyApiClient
113
115
 
114
116
  # Provides a shorthand for `raise` option.
115
117
  # `MyApiClient::Error` requires `MyApiClient::Params::Params` instance on
116
- # initialize, but it makes trubolesome. `MyApiClient::NetworkError` is more.
118
+ # initialize, but it makes troublesome. `MyApiClient::NetworkError` is more.
117
119
  # If given a error instance, it will return raw value without processing.
118
120
  #
119
- # @param exception [Clsas, MyApiClient::Error] Processing target.
120
- # @param response [Hash] describe_response_here
121
- # @param status_code [Integer] describe_status_code_here
121
+ # @param options [Hash] Stubbing options.
122
+ # @option options [Class, MyApiClient::Error] :raise Processing target.
123
+ # @option options [Hash] :response Stubbed response body.
124
+ # @option options [Integer] :status_code Stubbed status code (defaults to 400).
125
+ # @option options [Hash] :headers
126
+ # Stubbed response headers. Keys are looked up case-insensitively like real
127
+ # response headers and values are converted to Strings, so prefer String keys
128
+ # (e.g. `'X-Request-Id'`).
122
129
  # @return [MyApiClient::Error] Processed exception.
123
130
  # @raise [RuntimeError] Unsupported error class was set.
124
- def process_raise_option(exception, response, status_code)
125
- case exception
131
+ def process_raise_option(options)
132
+ case options[:raise]
126
133
  when Class
127
- params = MyApiClient::Params::Params.new(nil, stub_as_response(response, status_code))
128
- if exception == MyApiClient::NetworkError
129
- exception.new(params, Net::OpenTimeout.new)
130
- else
131
- exception.new(params)
132
- end
134
+ build_stubbed_error(*options.values_at(:raise, :response, :status_code, :headers))
133
135
  when MyApiClient::Error
134
- raise ERROR_MESSAGE if response.present?
136
+ raise ERROR_MESSAGE if options.values_at(:response, :status_code, :headers).any?(&:present?)
137
+
138
+ options[:raise]
139
+ else
140
+ raise "Unsupported error class was set: #{options[:raise].inspect}"
141
+ end
142
+ end
135
143
 
136
- exception
144
+ def build_stubbed_error(exception, response, status_code, headers)
145
+ stubbed_response = stub_as_response(response, status_code, headers)
146
+ params = MyApiClient::Params::Params.new(nil, stubbed_response)
147
+ if exception == MyApiClient::NetworkError
148
+ exception.new(params, Net::OpenTimeout.new)
137
149
  else
138
- raise "Unsupported error class was set: #{exception.inspect}"
150
+ exception.new(params)
139
151
  end
140
152
  end
141
153
 
142
- def stub_as_response(params, status_code)
154
+ def stub_as_response(params, status_code, headers = nil)
143
155
  instance_double(
144
156
  Sawyer::Response,
145
157
  status: status_code.presence || 400,
146
- headers: {},
158
+ headers: Faraday::Utils::Headers.new(headers),
147
159
  data: stub_as_resource(params),
148
160
  body: params.to_json,
149
161
  timing: 0.123
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MyApiClient
4
- VERSION = '2.1.0'
4
+ VERSION = '2.2.0'
5
5
  end
data/my_api/Gemfile CHANGED
@@ -3,7 +3,7 @@
3
3
  source 'https://rubygems.org'
4
4
 
5
5
  gem 'puma', '>= 6.0'
6
- gem 'rails', '~> 8.1.3'
6
+ gem 'rails', '~> 8.1.4'
7
7
 
8
8
  group :development, :test do
9
9
  gem 'rspec-rails'