my_api_client 0.11.0 → 0.12.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 +4 -4
- data/.rubocop.yml +8 -1
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +2 -2
- data/README.jp.md +30 -0
- data/lib/my_api_client.rb +3 -0
- data/lib/my_api_client/base.rb +1 -1
- data/lib/my_api_client/error_handling.rb +12 -5
- data/lib/my_api_client/error_handling/generator.rb +23 -10
- data/lib/my_api_client/error_handling/process_retry_option.rb +50 -0
- data/lib/my_api_client/exceptions.rb +1 -1
- data/lib/my_api_client/rspec/matchers/be_handled_as_an_error.rb +4 -3
- data/lib/my_api_client/rspec/stub.rb +1 -1
- data/lib/my_api_client/service_abstract.rb +22 -0
- data/lib/my_api_client/sleeper.rb +19 -0
- data/lib/my_api_client/version.rb +1 -1
- data/my_api_client.gemspec +2 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e5581dc65458d9130b465c89479fa8fc877c78f67d1cf701c225d64cbef9577
|
4
|
+
data.tar.gz: 86cae4eade33446a4ef2a5e54f44600e72ee868add6e3cfa5690fe8f1336df01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fce2d580f7c2622b2c2b1acc506e585434c29946ac81b6311e255cb53ac8e98276f30b79171e87610076376711f024b08b86724dcc5413328ba7488c9b52e983
|
7
|
+
data.tar.gz: 9475d69090e5748e511e7000df1db586da11ee5f62fc5f35fad30fce203a6ca2beabcafcf28e8eaf505e4a58d45cd4f771da86dea74bdcc70cee7e072267751e
|
data/.rubocop.yml
CHANGED
@@ -23,6 +23,9 @@ Metrics/MethodLength:
|
|
23
23
|
Metrics/LineLength:
|
24
24
|
Max: 100
|
25
25
|
|
26
|
+
Naming/AccessorMethodName:
|
27
|
+
Enabled: false
|
28
|
+
|
26
29
|
Style/ClassAndModuleChildren:
|
27
30
|
Exclude:
|
28
31
|
- 'spec/**/*'
|
@@ -33,6 +36,10 @@ Style/TrailingCommaInArrayLiteral:
|
|
33
36
|
Style/TrailingCommaInHashLiteral:
|
34
37
|
EnforcedStyleForMultiline: comma
|
35
38
|
|
39
|
+
RSpec/DescribeClass:
|
40
|
+
Exclude:
|
41
|
+
- 'spec/lib/my_api_client/rspec/matchers/**/*'
|
42
|
+
|
36
43
|
RSpec/ExampleLength:
|
37
44
|
Max: 10
|
38
45
|
|
@@ -43,7 +50,7 @@ RSpec/FilePath:
|
|
43
50
|
- 'spec/lib/my_api_client/rspec/**/*'
|
44
51
|
|
45
52
|
RSpec/NestedGroups:
|
46
|
-
Max:
|
53
|
+
Max: 5
|
47
54
|
|
48
55
|
RSpec/MultipleExpectations:
|
49
56
|
Max: 4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## v0.12.0 (Jan 19, 2020)
|
4
|
+
|
5
|
+
### Feature
|
6
|
+
|
7
|
+
* [#173](https://github.com/ryz310/my_api_client/pull/173) Avoid sleep on testing ([@ryz310](https://github.com/ryz310))
|
8
|
+
* [#175](https://github.com/ryz310/my_api_client/pull/175) Verify arguments on error handling definition ([@ryz310](https://github.com/ryz310))
|
9
|
+
* [#176](https://github.com/ryz310/my_api_client/pull/176) Provides a syntax sugar of `retry_on` on `error_handling` ([@ryz310](https://github.com/ryz310))
|
10
|
+
|
11
|
+
### Bugfix
|
12
|
+
|
13
|
+
* [#174](https://github.com/ryz310/my_api_client/pull/174) Fix warning on ruby 2.7 ([@ryz310](https://github.com/ryz310))
|
14
|
+
|
3
15
|
## v0.11.0 (Jan 16, 2020)
|
4
16
|
|
5
17
|
### Feature
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
my_api_client (0.
|
4
|
+
my_api_client (0.12.0)
|
5
5
|
activesupport (>= 4.2.0)
|
6
6
|
faraday (>= 0.17.1)
|
7
7
|
jsonpath
|
@@ -93,7 +93,7 @@ GEM
|
|
93
93
|
to_regexp (0.2.1)
|
94
94
|
tzinfo (1.2.6)
|
95
95
|
thread_safe (~> 0.1)
|
96
|
-
unicode-display_width (1.6.
|
96
|
+
unicode-display_width (1.6.1)
|
97
97
|
webmock (3.8.0)
|
98
98
|
addressable (>= 2.3.6)
|
99
99
|
crack (>= 0.3.2)
|
data/README.jp.md
CHANGED
@@ -228,6 +228,36 @@ API リクエストを何度も実行していると回線の不調などによ
|
|
228
228
|
|
229
229
|
ちなみに一応 `discard_on` も実装していますが、作者自身が有効な用途を見出せていないので、詳細は割愛します。良い利用方法があれば教えてください。
|
230
230
|
|
231
|
+
#### 便利な使い方
|
232
|
+
|
233
|
+
`error_handling` に `retry` オプションを付与する事で `retry_on` の定義を省略できます。
|
234
|
+
例えば以下の 2 つのコードは同じ意味になります。
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
retry_on MyApiClient::ApiLimitError, wait: 30.seconds, attempts: 3
|
238
|
+
error_handling json: { '$.errors.code': 20 },
|
239
|
+
raise: MyApiClient::ApiLimitError
|
240
|
+
```
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
error_handling json: { '$.errors.code': 20 },
|
244
|
+
raise: MyApiClient::ApiLimitError,
|
245
|
+
retry: { wait: 30.seconds, attempts: 3 }
|
246
|
+
```
|
247
|
+
|
248
|
+
`retry_on` で `wait` や `attempts` を指定する必要がない場合は `retry: true` という記述で動作します。
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
error_handling json: { '$.errors.code': 20 },
|
252
|
+
raise: MyApiClient::ApiLimitError,
|
253
|
+
retry: true
|
254
|
+
```
|
255
|
+
|
256
|
+
`retry` オプションを使用する際は以下の点に注意が必要です。
|
257
|
+
|
258
|
+
* `error_handling` に `raise` オプションの指定が必須となります。
|
259
|
+
* Block を使った `error_handling` の定義は禁止されます。
|
260
|
+
|
231
261
|
#### MyApiClient::NetworkError
|
232
262
|
|
233
263
|
前述の通りですが、 `MyApiClient` ではネットワーク系の例外はまとめて `MyApiClient::NetworkError` として `raise` されます。他の例外と同じく `MyApiClient::Error` を親クラスとしています。 `MyApiClient::NetworkError` として扱われる例外クラスの一覧は `MyApiClient::NETWORK_ERRORS` で参照できます。また、元となった例外は `#original_error` で参照できます。
|
data/lib/my_api_client.rb
CHANGED
@@ -7,9 +7,11 @@ require 'jsonpath'
|
|
7
7
|
require 'active_support'
|
8
8
|
require 'active_support/core_ext'
|
9
9
|
require 'sawyer'
|
10
|
+
require 'my_api_client/service_abstract'
|
10
11
|
require 'my_api_client/version'
|
11
12
|
require 'my_api_client/config'
|
12
13
|
require 'my_api_client/error_handling/generator'
|
14
|
+
require 'my_api_client/error_handling/process_retry_option'
|
13
15
|
require 'my_api_client/error_handling'
|
14
16
|
require 'my_api_client/exceptions'
|
15
17
|
require 'my_api_client/logger'
|
@@ -18,6 +20,7 @@ require 'my_api_client/params/params'
|
|
18
20
|
require 'my_api_client/params/request'
|
19
21
|
require 'my_api_client/request'
|
20
22
|
require 'my_api_client/base'
|
23
|
+
require 'my_api_client/sleeper'
|
21
24
|
|
22
25
|
# Loads gems for feature of integrations
|
23
26
|
begin
|
data/lib/my_api_client/base.rb
CHANGED
@@ -34,15 +34,22 @@ module MyApiClient
|
|
34
34
|
# @option with [Symbol]
|
35
35
|
# Calls specified method when error detected
|
36
36
|
# @option raise [MyApiClient::Error]
|
37
|
-
# Raises specified error when
|
37
|
+
# Raises specified error when an invalid response detected.
|
38
|
+
# Should be inherited `MyApiClient::Error` class.
|
39
|
+
# default: MyApiClient::Error
|
40
|
+
# @option retry [TrueClass, Hash]
|
41
|
+
# If the error detected, retries the API request. Requires `raise` option.
|
42
|
+
# You can set `true` or `retry_on` options (`wait` and `attempts`).
|
38
43
|
# @yield [MyApiClient::Params::Params, MyApiClient::Logger]
|
39
|
-
# Executes the block when error detected
|
44
|
+
# Executes the block when error detected.
|
45
|
+
# Forbid to be used with the` retry` option.
|
40
46
|
def error_handling(**options, &block)
|
41
|
-
options[:
|
42
|
-
|
47
|
+
options[:block] = block
|
48
|
+
retry_options = ProcessRetryOption.call(error_handling_options: options)
|
49
|
+
retry_on(options[:raise], **retry_options) if retry_options
|
43
50
|
|
44
51
|
temp = error_handlers.dup
|
45
|
-
temp << ->(response) { Generator.call(options.merge(response: response)) }
|
52
|
+
temp << ->(response) { Generator.call(**options.merge(response: response)) }
|
46
53
|
self.error_handlers = temp
|
47
54
|
end
|
48
55
|
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module MyApiClient
|
4
4
|
module ErrorHandling
|
5
5
|
# Generates an error handler proc (or symbol)
|
6
|
-
class Generator
|
7
|
-
|
6
|
+
class Generator < ServiceAbstract
|
7
|
+
ARGUMENTS = %i[response status_code json with raise block].freeze
|
8
8
|
|
9
9
|
# @param options [Hash]
|
10
10
|
# Options for this generator
|
@@ -25,17 +25,14 @@ module MyApiClient
|
|
25
25
|
# Returns value as `Proc` if given `raise` or `block` option
|
26
26
|
# @return [Symbol]
|
27
27
|
# Returns value as `Symbol` if given `with` option
|
28
|
-
def
|
29
|
-
|
28
|
+
def initialize(**options)
|
29
|
+
options[:raise] ||= MyApiClient::Error
|
30
|
+
verify_and_set_arguments(**options)
|
30
31
|
end
|
31
32
|
|
32
33
|
private
|
33
34
|
|
34
|
-
attr_reader
|
35
|
-
|
36
|
-
def initialize(**options)
|
37
|
-
options.each { |k, v| instance_variable_set("@_#{k}", v) }
|
38
|
-
end
|
35
|
+
attr_reader(*ARGUMENTS.map { |argument| :"_#{argument}" })
|
39
36
|
|
40
37
|
def call
|
41
38
|
return unless match?(_status_code, _response.status)
|
@@ -46,7 +43,23 @@ module MyApiClient
|
|
46
43
|
elsif _with
|
47
44
|
_with
|
48
45
|
else
|
49
|
-
->(params,
|
46
|
+
->(params, _) { raise _raise, params }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Verify given options and raise error if they are incorrect.
|
51
|
+
# If not, set them to instance variables.
|
52
|
+
#
|
53
|
+
# @param options [Hash]
|
54
|
+
# @raise [RuntimeError]
|
55
|
+
def verify_and_set_arguments(**options)
|
56
|
+
options.each do |k, v|
|
57
|
+
if ARGUMENTS.exclude? k
|
58
|
+
raise "Specified an incorrect option: `#{k}`\n" \
|
59
|
+
"You can use options that: #{ARGUMENTS}"
|
60
|
+
end
|
61
|
+
|
62
|
+
instance_variable_set("@_#{k}", v)
|
50
63
|
end
|
51
64
|
end
|
52
65
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
module ErrorHandling
|
5
|
+
# Processes the `retry` option.
|
6
|
+
class ProcessRetryOption < ServiceAbstract
|
7
|
+
# @param error_handling_options [Hash]
|
8
|
+
# Options for the retry.
|
9
|
+
# @option raise [MyApiClient::Error]
|
10
|
+
# Raises specified error when an invalid response detected.
|
11
|
+
# Should be inherited `MyApiClient::Error` class.
|
12
|
+
# @option retry [TrueClass, Hash]
|
13
|
+
# If the error detected, retries the API request. Requires `raise` option.
|
14
|
+
# You can set `true` or `retry_on` options (`wait` and `attempts`).
|
15
|
+
# @option block [Proc, nil]
|
16
|
+
# Executes the block when error detected.
|
17
|
+
# The `block` option is forbidden to be used with the` retry` option.
|
18
|
+
# @return [Hash]
|
19
|
+
# Options for `retry_on`.
|
20
|
+
# @return [nil]
|
21
|
+
# If `retry` is not specified.
|
22
|
+
def initialize(error_handling_options:)
|
23
|
+
@error_handling_options = error_handling_options
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :error_handling_options
|
29
|
+
|
30
|
+
def call
|
31
|
+
retry_options = error_handling_options.delete(:retry)
|
32
|
+
return unless retry_options
|
33
|
+
|
34
|
+
verify_error_handling_options
|
35
|
+
retry_options = {} unless retry_options.is_a? Hash
|
36
|
+
retry_options
|
37
|
+
end
|
38
|
+
|
39
|
+
# Requires `retry` option and forbid `block` option.
|
40
|
+
def verify_error_handling_options
|
41
|
+
if !error_handling_options[:raise]
|
42
|
+
raise 'The `retry` option requires `raise` option. ' \
|
43
|
+
'Please set any `raise` option, which inherits `MyApiClient::Error` class.'
|
44
|
+
elsif error_handling_options[:block]
|
45
|
+
raise 'The `block` option is forbidden to be used with the` retry` option.'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -16,9 +16,9 @@ RSpec::Matchers.define :be_handled_as_an_error do |expected_error_class|
|
|
16
16
|
handle_error(api_request).nil?
|
17
17
|
end
|
18
18
|
|
19
|
-
chain
|
20
|
-
chain(:times) {
|
21
|
-
chain
|
19
|
+
chain(:after_retry, :retry_count)
|
20
|
+
chain(:times) {}
|
21
|
+
chain(:when_receive, :expected_response)
|
22
22
|
|
23
23
|
description do
|
24
24
|
message = "be handled as #{expected_error_class || 'an error'}"
|
@@ -54,6 +54,7 @@ RSpec::Matchers.define :be_handled_as_an_error do |expected_error_class|
|
|
54
54
|
)
|
55
55
|
@sawyer = instance_double(Sawyer::Agent, call: response)
|
56
56
|
allow(Sawyer::Agent).to receive(:new).and_return(sawyer)
|
57
|
+
allow(MyApiClient::Sleeper).to receive(:call)
|
57
58
|
end
|
58
59
|
|
59
60
|
def set_validation_for_retry_count
|
@@ -23,7 +23,7 @@ module MyApiClient
|
|
23
23
|
# @return [InstanceDouble]
|
24
24
|
# Returns a spy object of the stubbed ApiClient.
|
25
25
|
def stub_api_client_all(klass, **actions_and_options)
|
26
|
-
instance = stub_api_client(klass, actions_and_options)
|
26
|
+
instance = stub_api_client(klass, **actions_and_options)
|
27
27
|
allow(klass).to receive(:new).and_return(instance)
|
28
28
|
instance
|
29
29
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
# The abstract class for service classes
|
5
|
+
class ServiceAbstract
|
6
|
+
private_class_method :new
|
7
|
+
|
8
|
+
def self.call(**args, &block)
|
9
|
+
new(**args, &block).send(:call)
|
10
|
+
end
|
11
|
+
|
12
|
+
# private
|
13
|
+
|
14
|
+
# def initialize(**_args)
|
15
|
+
# raise "You must implement #{self.class}##{__method__}"
|
16
|
+
# end
|
17
|
+
|
18
|
+
# def call
|
19
|
+
# raise "You must implement #{self.class}##{__method__}"
|
20
|
+
# end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
# Sleep arbitrary time
|
5
|
+
class Sleeper < ServiceAbstract
|
6
|
+
# @param wait [Integer, Float] Sleep time
|
7
|
+
def initialize(wait:)
|
8
|
+
@wait = wait
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :wait
|
14
|
+
|
15
|
+
def call
|
16
|
+
sleep(wait)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/my_api_client.gemspec
CHANGED
@@ -22,6 +22,8 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ['lib']
|
24
24
|
|
25
|
+
spec.required_ruby_version = '>= 2.4.0'
|
26
|
+
|
25
27
|
spec.add_dependency 'activesupport', '>= 4.2.0'
|
26
28
|
spec.add_dependency 'faraday', '>= 0.17.1'
|
27
29
|
spec.add_dependency 'jsonpath'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: my_api_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ryz310
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -262,6 +262,7 @@ files:
|
|
262
262
|
- lib/my_api_client/config.rb
|
263
263
|
- lib/my_api_client/error_handling.rb
|
264
264
|
- lib/my_api_client/error_handling/generator.rb
|
265
|
+
- lib/my_api_client/error_handling/process_retry_option.rb
|
265
266
|
- lib/my_api_client/errors.rb
|
266
267
|
- lib/my_api_client/exceptions.rb
|
267
268
|
- lib/my_api_client/integrations/bugsnag.rb
|
@@ -274,6 +275,8 @@ files:
|
|
274
275
|
- lib/my_api_client/rspec/matchers/be_handled_as_an_error.rb
|
275
276
|
- lib/my_api_client/rspec/matchers/request_to.rb
|
276
277
|
- lib/my_api_client/rspec/stub.rb
|
278
|
+
- lib/my_api_client/service_abstract.rb
|
279
|
+
- lib/my_api_client/sleeper.rb
|
277
280
|
- lib/my_api_client/version.rb
|
278
281
|
- my_api_client.gemspec
|
279
282
|
- renovate.json
|
@@ -289,7 +292,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
289
292
|
requirements:
|
290
293
|
- - ">="
|
291
294
|
- !ruby/object:Gem::Version
|
292
|
-
version:
|
295
|
+
version: 2.4.0
|
293
296
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
294
297
|
requirements:
|
295
298
|
- - ">="
|