my_api_client 0.13.0 → 0.14.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|