my_api_client 0.13.0 → 0.14.0.pre
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/.circleci/config.yml +1 -1
- data/.dependabot/config.yml +16 -0
- data/.rubocop.yml +4 -10
- data/.rubocop_todo.yml +1 -11
- data/CHANGELOG.md +78 -0
- data/Gemfile.lock +11 -9
- data/README.jp.md +2 -2
- data/lib/my_api_client.rb +3 -2
- data/lib/my_api_client/base.rb +0 -18
- data/lib/my_api_client/config.rb +0 -29
- data/lib/my_api_client/error_handling.rb +7 -17
- data/lib/my_api_client/error_handling/generator.rb +9 -5
- data/lib/my_api_client/error_handling/{process_retry_option.rb → retry_option_processor.rb} +1 -1
- data/lib/my_api_client/params/request.rb +7 -10
- data/lib/my_api_client/request.rb +54 -71
- data/lib/my_api_client/request/executor.rb +89 -0
- data/lib/my_api_client/request/logger.rb +37 -0
- data/lib/my_api_client/rspec/matcher_helper.rb +2 -2
- data/lib/my_api_client/rspec/matchers/be_handled_as_an_error.rb +2 -0
- data/lib/my_api_client/version.rb +1 -1
- data/my_api_client.gemspec +1 -1
- data/renovate.json +16 -0
- metadata +12 -10
- data/lib/my_api_client/logger.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d52de78feca8df4a1daac75f796382190d0f383c5f0e379111544d18ae863627
|
4
|
+
data.tar.gz: 76fd03b48893738aa1a1953592c877eba6dd43a6b9c4066a197453f9425ecfa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95069064c4d7e6f31abbe302db40d11f574726c11631513d3e40b3fd158e77e95ab81079d0fd4033833aac826722455938fc69605acbee0c2ecb58b11a3c949f
|
7
|
+
data.tar.gz: 2c5fceee08ba837afb4901feca3d531e09c8a5d4c2ba6756b2eddd9f185050686e1eed304e077f82aa2f4aa85fe1cb723c17ec7de32470210fc1347cc94ea5fa
|
data/.circleci/config.yml
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
version: 1
|
2
|
+
update_configs:
|
3
|
+
- package_manager: "ruby:bundler"
|
4
|
+
directory: "/"
|
5
|
+
update_schedule: "daily"
|
6
|
+
default_reviewers:
|
7
|
+
- "ryz310"
|
8
|
+
default_labels:
|
9
|
+
- "dependabot"
|
10
|
+
automerged_updates:
|
11
|
+
- match:
|
12
|
+
dependency_type: "development"
|
13
|
+
update_type: "all"
|
14
|
+
- match:
|
15
|
+
dependency_type: "production"
|
16
|
+
update_type: "semver:patch"
|
data/.rubocop.yml
CHANGED
@@ -7,11 +7,10 @@ inherit_from: .rubocop_todo.yml
|
|
7
7
|
AllCops:
|
8
8
|
TargetRubyVersion: 2.4
|
9
9
|
|
10
|
-
|
11
|
-
Max:
|
10
|
+
Layout/LineLength:
|
11
|
+
Max: 100
|
12
12
|
|
13
13
|
Metrics/BlockLength:
|
14
|
-
Max: 50
|
15
14
|
Exclude:
|
16
15
|
- 'my_api_client.gemspec'
|
17
16
|
- 'lib/my_api_client/rspec/matchers/**/*'
|
@@ -20,15 +19,10 @@ Metrics/BlockLength:
|
|
20
19
|
Metrics/MethodLength:
|
21
20
|
Max: 15
|
22
21
|
|
23
|
-
Metrics/LineLength:
|
24
|
-
Max: 100
|
25
|
-
|
26
22
|
Naming/AccessorMethodName:
|
27
|
-
Enabled: false
|
28
|
-
|
29
|
-
Style/ClassAndModuleChildren:
|
30
23
|
Exclude:
|
31
|
-
-
|
24
|
+
- spec/dummy_app/api_clients/example_api_client.rb
|
25
|
+
- spec/lib/my_api_client/rspec/matchers/be_handled_as_an_error_spec.rb
|
32
26
|
|
33
27
|
Style/TrailingCommaInArrayLiteral:
|
34
28
|
EnforcedStyleForMultiline: comma
|
data/.rubocop_todo.yml
CHANGED
@@ -1,17 +1,7 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2020-
|
3
|
+
# on 2020-02-21 23:30:47 +0000 using RuboCop version 0.80.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
|
-
|
9
|
-
# Offense count: 18
|
10
|
-
RSpec/LeakyConstantDeclaration:
|
11
|
-
Exclude:
|
12
|
-
- 'spec/lib/my_api_client/base_spec.rb'
|
13
|
-
- 'spec/lib/my_api_client/config_spec.rb'
|
14
|
-
- 'spec/lib/my_api_client/error_handling_spec.rb'
|
15
|
-
- 'spec/lib/my_api_client/exceptions_spec.rb'
|
16
|
-
- 'spec/lib/my_api_client/request_spec.rb'
|
17
|
-
- 'spec/lib/my_api_client/rspec/stub_spec.rb'
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,83 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## v0.14.0.pre (Feb 23, 2020)
|
4
|
+
|
5
|
+
### Refactoring
|
6
|
+
|
7
|
+
* [#179](https://github.com/ryz310/my_api_client/pull/179) Change the "with" option structure ([@ryz310](https://github.com/ryz310))
|
8
|
+
* [#206](https://github.com/ryz310/my_api_client/pull/206) Rebuild api request processing ([@ryz310](https://github.com/ryz310))
|
9
|
+
* [#207](https://github.com/ryz310/my_api_client/pull/207) Fix offending codes ([@ryz310](https://github.com/ryz310))
|
10
|
+
|
11
|
+
### Breaking Change
|
12
|
+
|
13
|
+
* [#196](https://github.com/ryz310/my_api_client/pull/196) Change the request structure ([@ryz310](https://github.com/ryz310))
|
14
|
+
|
15
|
+
> ### logging
|
16
|
+
>
|
17
|
+
> **before**
|
18
|
+
>
|
19
|
+
> ```
|
20
|
+
> I, [2020-02-02T15:26:53.788092 #93220] INFO -- : API request `GET https://api.esa.io/v1/teams/feedforce/posts`: "Start"
|
21
|
+
> I, [2020-02-02T15:26:55.760452 #93220] INFO -- : API request `GET https://api.esa.io/v1/teams/feedforce/posts`: "Duration 1.97186 sec"
|
22
|
+
> I, [2020-02-02T15:26:55.760739 #93220] INFO -- : API request `GET https://api.esa.io/v1/teams/feedforce/posts`: "Success (200)"
|
23
|
+
> ```
|
24
|
+
>
|
25
|
+
> **after**
|
26
|
+
>
|
27
|
+
> Shows URL with query strings.
|
28
|
+
>
|
29
|
+
> ```
|
30
|
+
> I, [2020-02-02T15:20:47.471040 #90870] INFO -- : API request `GET https://api.esa.io/v1/teams/feedforce/posts?page=1&per_page=100&q=user%3Aryosuke_sato+category%3Aunsorted`: "Start"
|
31
|
+
> I, [2020-02-02T15:20:49.516099 #90870] INFO -- : API request `GET https://api.esa.io/v1/teams/feedforce/posts?page=1&per_page=100&q=user%3Aryosuke_sato+category%3Aunsorted`: "Duration 2.034907 sec"
|
32
|
+
> I, [2020-02-02T15:20:49.516391 #90870] INFO -- : API request `GET https://api.esa.io/v1/teams/feedforce/posts?page=1&per_page=100&q=user%3Aryosuke_sato+category%3Aunsorted`: "Success (200)"
|
33
|
+
> ```
|
34
|
+
>
|
35
|
+
> ### MyApiClient::Params::Request
|
36
|
+
>
|
37
|
+
> **before**
|
38
|
+
>
|
39
|
+
> ```rb
|
40
|
+
> request_params.metadata # =>
|
41
|
+
> # {
|
42
|
+
> # line: 'GET path/to/resource',
|
43
|
+
> # headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
44
|
+
> # query: { key: 'value' }
|
45
|
+
> # }
|
46
|
+
> ```
|
47
|
+
>
|
48
|
+
> **after**
|
49
|
+
>
|
50
|
+
> The `#metadata` does not include `query` key and then includes full URL into `line` value.
|
51
|
+
>
|
52
|
+
> ```rb
|
53
|
+
> request_params.metadata # =>
|
54
|
+
> # {
|
55
|
+
> # line: 'GET https://example.com/path/to/resource?key=value',
|
56
|
+
> # headers: { 'Content-Type': 'application/json; charset=utf-8' }
|
57
|
+
> # }
|
58
|
+
> ```
|
59
|
+
|
60
|
+
### Rubocop Challenge
|
61
|
+
|
62
|
+
* [#205](https://github.com/ryz310/my_api_client/pull/205) Re-generate .rubocop_todo.yml with RuboCop v0.80.0 ([@ryz310](https://github.com/ryz310))
|
63
|
+
|
64
|
+
### Dependabot
|
65
|
+
|
66
|
+
* [#190](https://github.com/ryz310/my_api_client/pull/190) Add a config file of the dependabot ([@ryz310](https://github.com/ryz310))
|
67
|
+
* [#183](https://github.com/ryz310/my_api_client/pull/183) Bump pry-byebug from 3.7.0 to 3.8.0 ([@ryz310](https://github.com/ryz310))
|
68
|
+
* [#194](https://github.com/ryz310/my_api_client/pull/194) Bump bugsnag from 6.12.2 to 6.13.0 ([@ryz310](https://github.com/ryz310))
|
69
|
+
* [#197](https://github.com/ryz310/my_api_client/pull/197) Bump webmock from 3.8.0 to 3.8.1 ([@ryz310](https://github.com/ryz310))
|
70
|
+
* [#199](https://github.com/ryz310/my_api_client/pull/199) Bump webmock from 3.8.1 to 3.8.2 ([@ryz310](https://github.com/ryz310))
|
71
|
+
|
72
|
+
### Renovate
|
73
|
+
|
74
|
+
* [#193](https://github.com/ryz310/my_api_client/pull/193) Change renovate automerge setting ([@ryz310](https://github.com/ryz310))
|
75
|
+
* [#189](https://github.com/ryz310/my_api_client/pull/189) Update the renovate settings ([@ryz310](https://github.com/ryz310))
|
76
|
+
* [#184](https://github.com/ryz310/my_api_client/pull/184) Update ruby-orbs orb to v1.5.1 ([@ryz310](https://github.com/ryz310))
|
77
|
+
* [#185](https://github.com/ryz310/my_api_client/pull/185) Update ruby-orbs orb to v1.5.4 ([@ryz310](https://github.com/ryz310))
|
78
|
+
* [#187](https://github.com/ryz310/my_api_client/pull/187) Update ruby-orbs orb to v1.5.6 ([@ryz310](https://github.com/ryz310))
|
79
|
+
* [#192](https://github.com/ryz310/my_api_client/pull/192) Update ruby-orbs orb to v1.6.0 ([@ryz310](https://github.com/ryz310))
|
80
|
+
|
3
81
|
## v0.13.0 (Jan 21, 2020)
|
4
82
|
|
5
83
|
### 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.14.0.pre)
|
5
5
|
activesupport (>= 4.2.0)
|
6
6
|
faraday (>= 0.17.1)
|
7
7
|
jsonpath
|
@@ -18,11 +18,11 @@ GEM
|
|
18
18
|
addressable (2.7.0)
|
19
19
|
public_suffix (>= 2.0.2, < 5.0)
|
20
20
|
ast (2.4.0)
|
21
|
-
bugsnag (6.
|
21
|
+
bugsnag (6.13.0)
|
22
22
|
concurrent-ruby (~> 1.0)
|
23
|
-
byebug (11.1.
|
23
|
+
byebug (11.1.1)
|
24
24
|
coderay (1.1.2)
|
25
|
-
concurrent-ruby (1.1.
|
25
|
+
concurrent-ruby (1.1.6)
|
26
26
|
crack (0.4.3)
|
27
27
|
safe_yaml (~> 1.0.0)
|
28
28
|
diff-lcs (1.3)
|
@@ -47,12 +47,13 @@ GEM
|
|
47
47
|
pry (0.12.2)
|
48
48
|
coderay (~> 1.1.0)
|
49
49
|
method_source (~> 0.9.0)
|
50
|
-
pry-byebug (3.
|
50
|
+
pry-byebug (3.8.0)
|
51
51
|
byebug (~> 11.0)
|
52
52
|
pry (~> 0.10)
|
53
53
|
public_suffix (4.0.3)
|
54
54
|
rainbow (3.0.0)
|
55
55
|
rake (13.0.1)
|
56
|
+
rexml (3.2.4)
|
56
57
|
rspec (3.9.0)
|
57
58
|
rspec-core (~> 3.9.0)
|
58
59
|
rspec-expectations (~> 3.9.0)
|
@@ -68,16 +69,17 @@ GEM
|
|
68
69
|
rspec-support (3.9.2)
|
69
70
|
rspec_junit_formatter (0.4.1)
|
70
71
|
rspec-core (>= 2, < 4, != 2.12.0)
|
71
|
-
rubocop (0.
|
72
|
+
rubocop (0.80.0)
|
72
73
|
jaro_winkler (~> 1.5.1)
|
73
74
|
parallel (~> 1.10)
|
74
75
|
parser (>= 2.7.0.1)
|
75
76
|
rainbow (>= 2.2.2, < 4.0)
|
77
|
+
rexml
|
76
78
|
ruby-progressbar (~> 1.7)
|
77
79
|
unicode-display_width (>= 1.4.0, < 1.7)
|
78
80
|
rubocop-performance (1.5.2)
|
79
81
|
rubocop (>= 0.71.0)
|
80
|
-
rubocop-rspec (1.
|
82
|
+
rubocop-rspec (1.38.1)
|
81
83
|
rubocop (>= 0.68.1)
|
82
84
|
ruby-progressbar (1.10.1)
|
83
85
|
safe_yaml (1.0.5)
|
@@ -94,7 +96,7 @@ GEM
|
|
94
96
|
tzinfo (1.2.6)
|
95
97
|
thread_safe (~> 0.1)
|
96
98
|
unicode-display_width (1.6.1)
|
97
|
-
webmock (3.8.
|
99
|
+
webmock (3.8.2)
|
98
100
|
addressable (>= 2.3.6)
|
99
101
|
crack (>= 0.3.2)
|
100
102
|
hashdiff (>= 0.4.0, < 2.0.0)
|
@@ -115,7 +117,7 @@ DEPENDENCIES
|
|
115
117
|
rubocop
|
116
118
|
rubocop-performance
|
117
119
|
rubocop-rspec
|
118
|
-
simplecov
|
120
|
+
simplecov (= 0.17.1)
|
119
121
|
webmock
|
120
122
|
yard
|
121
123
|
|
data/README.jp.md
CHANGED
@@ -105,7 +105,7 @@ class ExampleApiClient < MyApiClient::Base
|
|
105
105
|
private
|
106
106
|
|
107
107
|
# @param params [MyApiClient::Params::Params] HTTP req and res params
|
108
|
-
# @param logger [MyApiClient::Logger] Logger for a request processing
|
108
|
+
# @param logger [MyApiClient::Request::Logger] Logger for a request processing
|
109
109
|
def my_error_handling(params, logger)
|
110
110
|
logger.warn "Response Body: #{params.response.body.inspect}"
|
111
111
|
raise MyApiClient::ClientError, params
|
@@ -163,7 +163,7 @@ error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
|
163
163
|
|
164
164
|
```ruby
|
165
165
|
# @param params [MyApiClient::Params::Params] HTTP req and res params
|
166
|
-
# @param logger [MyApiClient::Logger] Logger for a request processing
|
166
|
+
# @param logger [MyApiClient::Request::Logger] Logger for a request processing
|
167
167
|
def my_error_handling(params, logger)
|
168
168
|
logger.warn "Response Body: #{params.response.body.inspect}"
|
169
169
|
raise MyApiClient::ClientError, params
|
data/lib/my_api_client.rb
CHANGED
@@ -11,10 +11,11 @@ require 'my_api_client/service_abstract'
|
|
11
11
|
require 'my_api_client/version'
|
12
12
|
require 'my_api_client/config'
|
13
13
|
require 'my_api_client/error_handling/generator'
|
14
|
-
require 'my_api_client/error_handling/
|
14
|
+
require 'my_api_client/error_handling/retry_option_processor'
|
15
15
|
require 'my_api_client/error_handling'
|
16
16
|
require 'my_api_client/exceptions'
|
17
|
-
require 'my_api_client/logger'
|
17
|
+
require 'my_api_client/request/logger'
|
18
|
+
require 'my_api_client/request/executor'
|
18
19
|
require 'my_api_client/errors'
|
19
20
|
require 'my_api_client/params/params'
|
20
21
|
require 'my_api_client/params/request'
|
data/lib/my_api_client/base.rb
CHANGED
@@ -21,23 +21,5 @@ module MyApiClient
|
|
21
21
|
# NOTE: This class **MUST NOT** implement #initialize method. Because it
|
22
22
|
# will become constraint that need call #super in the #initialize at
|
23
23
|
# definition of the child classes.
|
24
|
-
|
25
|
-
HTTP_METHODS = %i[get post patch delete].freeze
|
26
|
-
|
27
|
-
HTTP_METHODS.each do |http_method|
|
28
|
-
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
29
|
-
# Description of ##{http_method}
|
30
|
-
#
|
31
|
-
# @param pathname [String]
|
32
|
-
# @param headers [Hash, nil]
|
33
|
-
# @param query [Hash, nil]
|
34
|
-
# @param body [Hash, nil]
|
35
|
-
# @return [Sawyer::Resouce] description_of_returned_object
|
36
|
-
def #{http_method}(pathname, headers: nil, query: nil, body: nil)
|
37
|
-
_request :#{http_method}, pathname, headers, query, body, logger
|
38
|
-
end
|
39
|
-
METHOD
|
40
|
-
end
|
41
|
-
alias put patch
|
42
24
|
end
|
43
25
|
end
|
data/lib/my_api_client/config.rb
CHANGED
@@ -16,34 +16,5 @@ module MyApiClient
|
|
16
16
|
METHOD
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
20
|
-
# Extracts schema and hostname from endpoint
|
21
|
-
#
|
22
|
-
# @example Extracts schema and hostname from 'https://example.com/path/to/api'
|
23
|
-
# schema_and_hostname # => 'https://example.com'
|
24
|
-
# @return [String] description_of_returned_object
|
25
|
-
def schema_and_hostname
|
26
|
-
if _uri.default_port == _uri.port
|
27
|
-
"#{_uri.scheme}://#{_uri.host}"
|
28
|
-
else
|
29
|
-
"#{_uri.scheme}://#{_uri.host}:#{_uri.port}"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# Extracts pathname from endpoint
|
34
|
-
#
|
35
|
-
# @example Extracts pathname from 'https://example.com/path/to/api'
|
36
|
-
# common_path # => 'path/to/api'
|
37
|
-
# @return [String] The pathanem
|
38
|
-
def common_path
|
39
|
-
_uri.path
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
# @return [URI] Returns a memoized URI instance
|
45
|
-
def _uri
|
46
|
-
@_uri ||= URI.parse(endpoint)
|
47
|
-
end
|
48
19
|
end
|
49
20
|
end
|
@@ -40,30 +40,20 @@ module MyApiClient
|
|
40
40
|
# @option retry [TrueClass, Hash]
|
41
41
|
# If the error detected, retries the API request. Requires `raise` option.
|
42
42
|
# You can set `true` or `retry_on` options (`wait` and `attempts`).
|
43
|
-
# @yield [MyApiClient::Params::Params, MyApiClient::Logger]
|
43
|
+
# @yield [MyApiClient::Params::Params, MyApiClient::Request::Logger]
|
44
44
|
# Executes the block when error detected.
|
45
45
|
# Forbid to be used with the` retry` option.
|
46
46
|
def error_handling(**options, &block)
|
47
47
|
options[:block] = block
|
48
|
-
retry_options =
|
48
|
+
retry_options = RetryOptionProcessor.call(error_handling_options: options)
|
49
49
|
retry_on(options[:raise], **retry_options) if retry_options
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
new_error_handlers = error_handlers.dup
|
52
|
+
new_error_handlers << lambda { |instance, response|
|
53
|
+
Generator.call(**options.merge(instance: instance, response: response))
|
54
|
+
}
|
55
|
+
self.error_handlers = new_error_handlers
|
54
56
|
end
|
55
57
|
end
|
56
|
-
|
57
|
-
# The error handlers defined later takes precedence
|
58
|
-
#
|
59
|
-
# @param response [Sawyer::Response] describe_params_here
|
60
|
-
# @return [Proc, Symbol, nil] description_of_returned_object
|
61
|
-
def error_handling(response)
|
62
|
-
error_handlers.reverse_each do |error_handler|
|
63
|
-
result = error_handler.call(response)
|
64
|
-
return result unless result.nil?
|
65
|
-
end
|
66
|
-
nil
|
67
|
-
end
|
68
58
|
end
|
69
59
|
end
|
@@ -4,10 +4,12 @@ module MyApiClient
|
|
4
4
|
module ErrorHandling
|
5
5
|
# Generates an error handler proc (or symbol)
|
6
6
|
class Generator < ServiceAbstract
|
7
|
-
ARGUMENTS = %i[response status_code json with raise block].freeze
|
7
|
+
ARGUMENTS = %i[instance response status_code json with raise block].freeze
|
8
8
|
|
9
9
|
# @param options [Hash]
|
10
10
|
# Options for this generator
|
11
|
+
# @option instance [MyApiClient::Base]
|
12
|
+
# The API client class.
|
11
13
|
# @option response [Sawyer::Response]
|
12
14
|
# The target of verifying
|
13
15
|
# @option status_code [String, Range, Integer, Regexp]
|
@@ -22,9 +24,7 @@ module MyApiClient
|
|
22
24
|
# @option block [Proc]
|
23
25
|
# Executes the block when error detected
|
24
26
|
# @return [Proc]
|
25
|
-
# Returns value as `Proc
|
26
|
-
# @return [Symbol]
|
27
|
-
# Returns value as `Symbol` if given `with` option
|
27
|
+
# Returns value as `Proc`.
|
28
28
|
def initialize(**options)
|
29
29
|
options[:raise] ||= MyApiClient::Error
|
30
30
|
verify_and_set_arguments(**options)
|
@@ -38,10 +38,14 @@ module MyApiClient
|
|
38
38
|
return unless match?(_status_code, _response.status)
|
39
39
|
return unless match_all?(_json, _response.body)
|
40
40
|
|
41
|
+
generate_error_handler
|
42
|
+
end
|
43
|
+
|
44
|
+
def generate_error_handler
|
41
45
|
if _block
|
42
46
|
->(params, logger) { _block.call(params, logger) }
|
43
47
|
elsif _with
|
44
|
-
_with
|
48
|
+
->(params, logger) { _instance.send(_with, params, logger) }
|
45
49
|
else
|
46
50
|
->(params, _) { raise _raise, params }
|
47
51
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module MyApiClient
|
4
4
|
module ErrorHandling
|
5
5
|
# Processes the `retry` option.
|
6
|
-
class
|
6
|
+
class RetryOptionProcessor < ServiceAbstract
|
7
7
|
# @param error_handling_options [Hash]
|
8
8
|
# Options for the retry.
|
9
9
|
# @option raise [MyApiClient::Error]
|
@@ -4,20 +4,18 @@ module MyApiClient
|
|
4
4
|
module Params
|
5
5
|
# Description of Params
|
6
6
|
class Request
|
7
|
-
attr_reader :method, :
|
7
|
+
attr_reader :method, :uri, :headers, :body
|
8
8
|
|
9
9
|
# Description of #initialize
|
10
10
|
#
|
11
11
|
# @param method [Symbol] describe_method_here
|
12
|
-
# @param
|
12
|
+
# @param uri [URI] describe_uri_here
|
13
13
|
# @param headers [Hash, nil] describe_headers_here
|
14
|
-
# @param query [Hash, nil] describe_query_here
|
15
14
|
# @param body [Hash, nil] describe_body_here
|
16
|
-
def initialize(method,
|
15
|
+
def initialize(method, uri, headers, body)
|
17
16
|
@method = method
|
18
|
-
@
|
17
|
+
@uri = uri
|
19
18
|
@headers = headers
|
20
|
-
@query = query
|
21
19
|
@body = body
|
22
20
|
end
|
23
21
|
|
@@ -25,7 +23,7 @@ module MyApiClient
|
|
25
23
|
#
|
26
24
|
# @return [Array<Object>] Arguments for Sawyer::Agent#call
|
27
25
|
def to_sawyer_args
|
28
|
-
[method,
|
26
|
+
[method, uri.to_s, body, { headers: headers }]
|
29
27
|
end
|
30
28
|
|
31
29
|
# Generate metadata for bugsnag.
|
@@ -34,9 +32,8 @@ module MyApiClient
|
|
34
32
|
# @return [Hash] Metadata for bugsnag
|
35
33
|
def metadata
|
36
34
|
{
|
37
|
-
line: "#{method.upcase} #{
|
35
|
+
line: "#{method.upcase} #{uri}",
|
38
36
|
headers: headers,
|
39
|
-
query: query,
|
40
37
|
body: body,
|
41
38
|
}.compact
|
42
39
|
end
|
@@ -46,7 +43,7 @@ module MyApiClient
|
|
46
43
|
#
|
47
44
|
# @return [String] Contents as string
|
48
45
|
def inspect
|
49
|
-
{ method: method,
|
46
|
+
{ method: method, uri: uri.to_s, headers: headers, body: body }.inspect
|
50
47
|
end
|
51
48
|
end
|
52
49
|
end
|
@@ -3,85 +3,68 @@
|
|
3
3
|
module MyApiClient
|
4
4
|
# Description of Request
|
5
5
|
module Request
|
6
|
-
|
7
|
-
#
|
8
|
-
# @param http_method [Symbol] describe_http_method_here
|
9
|
-
# @param pathname [String] describe_pathname_here
|
10
|
-
# @param headers [Hash, nil] describe_headers_here
|
11
|
-
# @param query [Hash, nil] describe_query_here
|
12
|
-
# @param body [Hash, nil] describe_body_here
|
13
|
-
# @param logger [::Logger] describe_logger_here
|
14
|
-
# @return [Sawyer::Resource] description_of_returned_object
|
15
|
-
# rubocop:disable Metrics/ParameterLists
|
16
|
-
def _request(http_method, pathname, headers, query, body, logger)
|
17
|
-
processed_path = [common_path, pathname].join('/').gsub('//', '/')
|
18
|
-
request_params = Params::Request.new(http_method, processed_path, headers, query, body)
|
19
|
-
agent # Initializes for faraday
|
20
|
-
request_logger = Logger.new(logger, faraday, http_method, processed_path)
|
21
|
-
call(:_execute, request_params, request_logger)
|
22
|
-
end
|
23
|
-
# rubocop:enable Metrics/ParameterLists
|
24
|
-
|
25
|
-
private
|
6
|
+
HTTP_METHODS = %i[get post patch delete].freeze
|
26
7
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
8
|
+
HTTP_METHODS.each do |http_method|
|
9
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
10
|
+
# Executes HTTP request with #{http_method.upcase} method
|
11
|
+
#
|
12
|
+
# @param pathname [String]
|
13
|
+
# Pathname of the request target URL.
|
14
|
+
# It's joined with the defined `endpoint`.
|
15
|
+
# @param headers [Hash, nil]
|
16
|
+
# Request headers.
|
17
|
+
# @param query [Hash, nil]
|
18
|
+
# Query string.
|
19
|
+
# @param body [Hash, nil]
|
20
|
+
# Request body. You should not specify it when use GET method.
|
21
|
+
# @return [Sawyer::Resouce]
|
22
|
+
# Response body instance.
|
23
|
+
def #{http_method}(pathname, headers: nil, query: nil, body: nil)
|
24
|
+
query_strings = query.present? ? '?' + query&.to_query : ''
|
25
|
+
uri = URI.join(File.join(endpoint, pathname), query_strings)
|
26
|
+
response = call(:_request, :#{http_method}, uri, headers, body)
|
27
|
+
response.data
|
28
|
+
end
|
29
|
+
METHOD
|
32
30
|
end
|
31
|
+
alias put patch
|
33
32
|
|
34
|
-
|
35
|
-
#
|
36
|
-
# @return [Faraday::Connection] description_of_returned_object
|
37
|
-
def faraday
|
38
|
-
@faraday ||=
|
39
|
-
Faraday.new(
|
40
|
-
nil,
|
41
|
-
request: {
|
42
|
-
timeout: (http_read_timeout if respond_to?(:http_read_timeout)),
|
43
|
-
open_timeout: (http_open_timeout if respond_to?(:http_open_timeout)),
|
44
|
-
}.compact
|
45
|
-
)
|
46
|
-
end
|
33
|
+
private
|
47
34
|
|
48
|
-
#
|
35
|
+
# Executes HTTP request.
|
49
36
|
#
|
50
|
-
# @param
|
51
|
-
#
|
52
|
-
# @
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
request_logger.
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
response.data
|
37
|
+
# @param http_method [Symbol]
|
38
|
+
# HTTP method. e.g. `:get`, `:post`, `:patch` and `:delete`.
|
39
|
+
# @param uri [URI]
|
40
|
+
# Request target URI including query strings.
|
41
|
+
# @param headers [Hash, nil]
|
42
|
+
# Request headers.
|
43
|
+
# @param body [Hash, nil]
|
44
|
+
# Request body.
|
45
|
+
# @return [Sawyer::Response]
|
46
|
+
# Response instance.
|
47
|
+
def _request(http_method, uri, headers, body)
|
48
|
+
request_params = Params::Request.new(http_method, uri, headers, body)
|
49
|
+
request_logger = Logger.new(logger, http_method, uri)
|
50
|
+
Executor.call(
|
51
|
+
instance: self,
|
52
|
+
request_params: request_params,
|
53
|
+
request_logger: request_logger,
|
54
|
+
faraday_options: faraday_options
|
55
|
+
)
|
70
56
|
end
|
71
57
|
|
72
|
-
#
|
58
|
+
# Generates options for the faraday instance.
|
73
59
|
#
|
74
|
-
# @
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
when Symbol
|
83
|
-
send(error_handler, params, request_logger)
|
84
|
-
end
|
60
|
+
# @return [Hash] Generated options.
|
61
|
+
def faraday_options
|
62
|
+
{
|
63
|
+
request: {
|
64
|
+
timeout: (http_read_timeout if respond_to?(:http_read_timeout)),
|
65
|
+
open_timeout: (http_open_timeout if respond_to?(:http_open_timeout)),
|
66
|
+
}.compact,
|
67
|
+
}
|
85
68
|
end
|
86
69
|
end
|
87
70
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
module Request
|
5
|
+
# Executes HTTP request with specified parameters.
|
6
|
+
class Executor < ServiceAbstract
|
7
|
+
# @param instance [MyApiClient::Base]
|
8
|
+
# The my_api_client instance.
|
9
|
+
# The instance method will be called on error handling.
|
10
|
+
# @param request_params [MyApiClient::Params::Request]
|
11
|
+
# Request parameter instance.
|
12
|
+
# @param request_logger [MyApiClient::Logger]
|
13
|
+
# Request logger instance.
|
14
|
+
# @param faraday_options [Hash]
|
15
|
+
# Options for the faraday instance. Mainly used for timeout settings.
|
16
|
+
# @return [Sawyer::Response]
|
17
|
+
# Response instance.
|
18
|
+
# @raise [MyApiClient::Error]
|
19
|
+
# Raises on invalid response or network errors.
|
20
|
+
def initialize(instance:, request_params:, request_logger:, faraday_options:)
|
21
|
+
@instance = instance
|
22
|
+
@request_params = request_params
|
23
|
+
@request_logger = request_logger
|
24
|
+
faraday = Faraday.new(nil, faraday_options)
|
25
|
+
@agent = Sawyer::Agent.new('', faraday: faraday)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :instance, :request_params, :request_logger, :agent
|
31
|
+
|
32
|
+
def call
|
33
|
+
request_logger.info('Start')
|
34
|
+
response = api_request
|
35
|
+
request_logger.info("Duration #{response.timing} sec")
|
36
|
+
verify(response)
|
37
|
+
rescue MyApiClient::Error => e
|
38
|
+
request_logger.warn("Failure (#{e.message})")
|
39
|
+
raise
|
40
|
+
else
|
41
|
+
request_logger.info("Success (#{response.status})")
|
42
|
+
response
|
43
|
+
end
|
44
|
+
|
45
|
+
# Executes HTTP request to the API.
|
46
|
+
#
|
47
|
+
# @return [Sawyer::Response]
|
48
|
+
# Response instance.
|
49
|
+
# @raise [MyApiClient::NetworkError]
|
50
|
+
# Raises on any network errors.
|
51
|
+
def api_request
|
52
|
+
agent.call(*request_params.to_sawyer_args)
|
53
|
+
rescue *NETWORK_ERRORS => e
|
54
|
+
params = Params::Params.new(request_params, nil)
|
55
|
+
raise MyApiClient::NetworkError.new(params, e)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Verifies the response.
|
59
|
+
#
|
60
|
+
# @param response_params [Sawyer::Response]
|
61
|
+
# The target response.
|
62
|
+
# @return [nil]
|
63
|
+
# Returns nil when a valid response.
|
64
|
+
# @raise [MyApiClient::Error]
|
65
|
+
# Raises on any invalid response.
|
66
|
+
def verify(response_params)
|
67
|
+
params = Params::Params.new(request_params, response_params)
|
68
|
+
find_error_handler(response_params)&.call(params, request_logger)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Executes response verifyment. If an invalid response is detected, return
|
72
|
+
# the error handler procedure. The error handlers defined later takes precedence.
|
73
|
+
#
|
74
|
+
# @param response_params [Sawyer::Response]
|
75
|
+
# The target response.
|
76
|
+
# @return [nil]
|
77
|
+
# Returns nil when a valid response.
|
78
|
+
# @return [Proc]
|
79
|
+
# Returns Proc when a invalid response.
|
80
|
+
def find_error_handler(response_params)
|
81
|
+
instance.error_handlers.reverse_each do |error_handler|
|
82
|
+
result = error_handler.call(instance, response_params)
|
83
|
+
return result unless result.nil?
|
84
|
+
end
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
module Request
|
5
|
+
# Description of Logger
|
6
|
+
class Logger
|
7
|
+
attr_reader :logger, :method, :uri
|
8
|
+
|
9
|
+
LOG_LEVEL = %i[debug info warn error fatal].freeze
|
10
|
+
|
11
|
+
# Description of #initialize
|
12
|
+
#
|
13
|
+
# @param logger [::Logger] describe_logger_here
|
14
|
+
# @param method [String] HTTP method
|
15
|
+
# @param uri [URI] Target URI
|
16
|
+
def initialize(logger, method, uri)
|
17
|
+
@logger = logger
|
18
|
+
@method = method.to_s.upcase
|
19
|
+
@uri = uri
|
20
|
+
end
|
21
|
+
|
22
|
+
LOG_LEVEL.each do |level|
|
23
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
24
|
+
def #{level}(message)
|
25
|
+
logger.#{level}(format(message))
|
26
|
+
end
|
27
|
+
METHOD
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def format(message)
|
33
|
+
"API request `#{method} #{uri}`: \"#{message}\""
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -4,8 +4,8 @@ module MyApiClient
|
|
4
4
|
# Helper module for rspec custom matcher
|
5
5
|
module MatcherHelper
|
6
6
|
def disable_logging
|
7
|
-
logger = instance_double(MyApiClient::Logger, info: nil, warn: nil)
|
8
|
-
allow(MyApiClient::Logger).to receive(:new).and_return(logger)
|
7
|
+
logger = instance_double(MyApiClient::Request::Logger, info: nil, warn: nil)
|
8
|
+
allow(MyApiClient::Request::Logger).to receive(:new).and_return(logger)
|
9
9
|
end
|
10
10
|
|
11
11
|
def dummy_response(status: 200, headers: {}, body: nil)
|
@@ -45,6 +45,7 @@ RSpec::Matchers.define :be_handled_as_an_error do |expected_error_class|
|
|
45
45
|
|
46
46
|
attr_reader :sawyer
|
47
47
|
|
48
|
+
# rubocop:disable Metrics/AbcSize
|
48
49
|
def init
|
49
50
|
disable_logging
|
50
51
|
response = dummy_response(
|
@@ -56,6 +57,7 @@ RSpec::Matchers.define :be_handled_as_an_error do |expected_error_class|
|
|
56
57
|
allow(Sawyer::Agent).to receive(:new).and_return(sawyer)
|
57
58
|
allow(MyApiClient::Sleeper).to receive(:call)
|
58
59
|
end
|
60
|
+
# rubocop:enable Metrics/AbcSize
|
59
61
|
|
60
62
|
def set_validation_for_retry_count
|
61
63
|
return if retry_count.nil?
|
data/my_api_client.gemspec
CHANGED
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.add_development_dependency 'rubocop'
|
38
38
|
spec.add_development_dependency 'rubocop-performance'
|
39
39
|
spec.add_development_dependency 'rubocop-rspec'
|
40
|
-
spec.add_development_dependency 'simplecov'
|
40
|
+
spec.add_development_dependency 'simplecov', '0.17.1'
|
41
41
|
spec.add_development_dependency 'webmock'
|
42
42
|
spec.add_development_dependency 'yard'
|
43
43
|
end
|
data/renovate.json
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
{
|
2
2
|
"extends": [
|
3
3
|
"config:base"
|
4
|
+
],
|
5
|
+
"packageRules": [
|
6
|
+
{
|
7
|
+
"updateTypes": ["major"],
|
8
|
+
"labels": ["renovate", "major"]
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"updateTypes": ["minor"],
|
12
|
+
"labels": ["renovate", "minor", "auto merge"],
|
13
|
+
"automerge": true
|
14
|
+
},
|
15
|
+
{
|
16
|
+
"updateTypes": ["patch"],
|
17
|
+
"labels": ["renovate", "patch", "auto merge"],
|
18
|
+
"automerge": true
|
19
|
+
}
|
4
20
|
]
|
5
21
|
}
|
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.14.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ryz310
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -182,16 +182,16 @@ dependencies:
|
|
182
182
|
name: simplecov
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
|
-
- -
|
185
|
+
- - '='
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
187
|
+
version: 0.17.1
|
188
188
|
type: :development
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
|
-
- -
|
192
|
+
- - '='
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version:
|
194
|
+
version: 0.17.1
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: webmock
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -228,6 +228,7 @@ extensions: []
|
|
228
228
|
extra_rdoc_files: []
|
229
229
|
files:
|
230
230
|
- ".circleci/config.yml"
|
231
|
+
- ".dependabot/config.yml"
|
231
232
|
- ".envrc.skeleton"
|
232
233
|
- ".gem_comet.yml"
|
233
234
|
- ".gitignore"
|
@@ -262,14 +263,15 @@ files:
|
|
262
263
|
- lib/my_api_client/config.rb
|
263
264
|
- lib/my_api_client/error_handling.rb
|
264
265
|
- lib/my_api_client/error_handling/generator.rb
|
265
|
-
- lib/my_api_client/error_handling/
|
266
|
+
- lib/my_api_client/error_handling/retry_option_processor.rb
|
266
267
|
- lib/my_api_client/errors.rb
|
267
268
|
- lib/my_api_client/exceptions.rb
|
268
269
|
- lib/my_api_client/integrations/bugsnag.rb
|
269
|
-
- lib/my_api_client/logger.rb
|
270
270
|
- lib/my_api_client/params/params.rb
|
271
271
|
- lib/my_api_client/params/request.rb
|
272
272
|
- lib/my_api_client/request.rb
|
273
|
+
- lib/my_api_client/request/executor.rb
|
274
|
+
- lib/my_api_client/request/logger.rb
|
273
275
|
- lib/my_api_client/rspec.rb
|
274
276
|
- lib/my_api_client/rspec/matcher_helper.rb
|
275
277
|
- lib/my_api_client/rspec/matchers/be_handled_as_an_error.rb
|
@@ -295,9 +297,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
295
297
|
version: 2.4.0
|
296
298
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
297
299
|
requirements:
|
298
|
-
- - "
|
300
|
+
- - ">"
|
299
301
|
- !ruby/object:Gem::Version
|
300
|
-
version:
|
302
|
+
version: 1.3.1
|
301
303
|
requirements: []
|
302
304
|
rubygems_version: 3.1.2
|
303
305
|
signing_key:
|
data/lib/my_api_client/logger.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MyApiClient
|
4
|
-
# Description of Logger
|
5
|
-
class Logger
|
6
|
-
attr_reader :logger, :method, :pathname
|
7
|
-
|
8
|
-
LOG_LEVEL = %i[debug info warn error fatal].freeze
|
9
|
-
|
10
|
-
# Description of #initialize
|
11
|
-
#
|
12
|
-
# @param logger [::Logger] describe_logger_here
|
13
|
-
# @param faraday [Faraday::Connection] describe_faraday_here
|
14
|
-
# @param method [String] HTTP method
|
15
|
-
# @param pathname [String] The path name
|
16
|
-
def initialize(logger, faraday, method, pathname)
|
17
|
-
@logger = logger
|
18
|
-
@method = method.to_s.upcase
|
19
|
-
@pathname = faraday.build_exclusive_url(pathname)
|
20
|
-
end
|
21
|
-
|
22
|
-
LOG_LEVEL.each do |level|
|
23
|
-
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
24
|
-
def #{level}(message)
|
25
|
-
logger.#{level}(format(message))
|
26
|
-
end
|
27
|
-
METHOD
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def format(message)
|
33
|
-
"API request `#{method} #{pathname}`: \"#{message}\""
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|