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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e287e051f0699595e499150dd4e4c303e00a82f951ffc86b13afde142a3720e
4
- data.tar.gz: 7725d581e64d01683a636f56e86d217010d536f827023d691faca3b5cbbe2264
3
+ metadata.gz: d52de78feca8df4a1daac75f796382190d0f383c5f0e379111544d18ae863627
4
+ data.tar.gz: 76fd03b48893738aa1a1953592c877eba6dd43a6b9c4066a197453f9425ecfa7
5
5
  SHA512:
6
- metadata.gz: c37ce83c7a27302b8e890087251c67b955e8398b95d08a78b47447401cf0b3332b9bcd66c0e46e4e578a5a51e80f0a4a5fcea576c69fd8d29be8fa5c1c670720
7
- data.tar.gz: 9a42a194c50def52f2aca6f9c54aac80dd7e4191114aa24fef543f81fab235417b3ec1f86ff2f960cd77cd1ff17188df5c073a4574df80fed9963375060058ce
6
+ metadata.gz: 95069064c4d7e6f31abbe302db40d11f574726c11631513d3e40b3fd158e77e95ab81079d0fd4033833aac826722455938fc69605acbee0c2ecb58b11a3c949f
7
+ data.tar.gz: 2c5fceee08ba837afb4901feca3d531e09c8a5d4c2ba6756b2eddd9f185050686e1eed304e077f82aa2f4aa85fe1cb723c17ec7de32470210fc1347cc94ea5fa
@@ -5,7 +5,7 @@
5
5
  version: 2.1
6
6
 
7
7
  orbs:
8
- ruby-orbs: sue445/ruby-orbs@1.4.5
8
+ ruby-orbs: sue445/ruby-orbs@1.6.0
9
9
  code-climate: rvla/code-climate@0.0.2
10
10
 
11
11
  references:
@@ -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"
@@ -7,11 +7,10 @@ inherit_from: .rubocop_todo.yml
7
7
  AllCops:
8
8
  TargetRubyVersion: 2.4
9
9
 
10
- Metrics/AbcSize:
11
- Max: 20
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
- - 'spec/**/*'
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
@@ -1,17 +1,7 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2020-01-08 23:41:00 +0000 using RuboCop version 0.79.0.
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'
@@ -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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- my_api_client (0.13.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.12.2)
21
+ bugsnag (6.13.0)
22
22
  concurrent-ruby (~> 1.0)
23
- byebug (11.1.0)
23
+ byebug (11.1.1)
24
24
  coderay (1.1.2)
25
- concurrent-ruby (1.1.5)
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.7.0)
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.79.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.37.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.0)
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
 
@@ -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
@@ -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/process_retry_option'
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'
@@ -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
@@ -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 = ProcessRetryOption.call(error_handling_options: options)
48
+ retry_options = RetryOptionProcessor.call(error_handling_options: options)
49
49
  retry_on(options[:raise], **retry_options) if retry_options
50
50
 
51
- temp = error_handlers.dup
52
- temp << ->(response) { Generator.call(**options.merge(response: response)) }
53
- self.error_handlers = temp
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` if given `raise` or `block` option
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 ProcessRetryOption < ServiceAbstract
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, :pathname, :headers, :query, :body
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 pathname [String] describe_pathname_here
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, pathname, headers, query, body)
15
+ def initialize(method, uri, headers, body)
17
16
  @method = method
18
- @pathname = pathname
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, pathname, body, { headers: headers, query: query }]
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} #{pathname}",
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, pathname: pathname, headers: headers, query: query, body: body }.inspect
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
- # Description of #_request
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
- # Description of #agent
28
- #
29
- # @return [Sawyer::Agent] description_of_returned_object
30
- def agent
31
- @agent ||= Sawyer::Agent.new(schema_and_hostname, faraday: faraday)
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
- # Description of #faraday
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
- # Description of #_execute
35
+ # Executes HTTP request.
49
36
  #
50
- # @param request_params [MyApiClient::Params::Request] describe_request_params_here
51
- # @param request_logger [MyApiClient::Logger] describe_request_logger_here
52
- # @return [Sawyer::Resource] description_of_returned_object
53
- # @raise [MyApiClient::Error]
54
- def _execute(request_params, request_logger)
55
- request_logger.info('Start')
56
- response = agent.call(*request_params.to_sawyer_args)
57
- request_logger.info("Duration #{response.timing} sec")
58
- params = Params::Params.new(request_params, response)
59
- _verify(params, request_logger)
60
- rescue *NETWORK_ERRORS => e
61
- params ||= Params::Params.new(request_params, nil)
62
- request_logger.error("Network Error (#{e.message})")
63
- raise MyApiClient::NetworkError.new(params, e)
64
- rescue MyApiClient::Error => e
65
- request_logger.warn("Failure (#{response.status})")
66
- raise e
67
- else
68
- request_logger.info("Success (#{response.status})")
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
- # Description of #_verify
58
+ # Generates options for the faraday instance.
73
59
  #
74
- # @param params [MyApiClient::Params::Params] describe_params_here
75
- # @param request_logger [MyApiClient::Logger] describe_request_logger_here
76
- # @return [nil] description_of_returned_object
77
- # @raise [MyApiClient::Error]
78
- def _verify(params, request_logger)
79
- case error_handler = error_handling(params.response)
80
- when Proc
81
- error_handler.call(params, request_logger)
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?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MyApiClient
4
- VERSION = '0.13.0'
4
+ VERSION = '0.14.0.pre'
5
5
  end
@@ -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
@@ -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.13.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-01-21 00:00:00.000000000 Z
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: '0'
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: '0'
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/process_retry_option.rb
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: '0'
302
+ version: 1.3.1
301
303
  requirements: []
302
304
  rubygems_version: 3.1.2
303
305
  signing_key:
@@ -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