gapic-common 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea69666c3f5162e9949825974c29af5ca636527a25e67d0ce034c2bb6c39b201
4
- data.tar.gz: 68df57288727233549f5ababcd296b545bd4a1e10bdc29caae1891019c3995ba
3
+ metadata.gz: dd16594f62fa1e7145513111074f9fb1ad6988ac38fcd0c7b7a63d119269e66d
4
+ data.tar.gz: 3c0921a7825bbab864a9a8fb370cd24def7493c2af050545e71d0dc22a4f980e
5
5
  SHA512:
6
- metadata.gz: 8c83345123a2739aa89f31aefb00288c8ae7e831af653a654872601a2e646ddd9b7d7356aa82e403b5c2571cae2bd437fbf4ff8c38e70822cfc18c89ea89f883
7
- data.tar.gz: a95b2ec76934bec8140e6c65b627644833143f313117cd86d867dcda0e3bfdf00407f86c8b33d0f52165de5549c3207119a8b5b506cba5b9da8c41a58846cf78
6
+ metadata.gz: b2b26d265c79563ff7bc28b74f3be6536df070d4bf7ed3e347d734ffadd867cb44f3dfac8f8a6b624f2786a0942643d92c5bdbc2610e3b0f1072f39b7337eef6
7
+ data.tar.gz: c02d9dfc4f98dc243d67a910e8a855a18333c3258f515e973962848c46812c9df52008fa942027592b451dce0e4b739fe7bf4553a81bf3bb649a71741c2da484
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Release History
2
2
 
3
+ ### 0.15.1 (2022-11-18)
4
+
5
+ #### Bug Fixes
6
+
7
+ * Fixed uninitialized constant when checking retry policy for a REST call ([#857](https://github.com/googleapis/gapic-generator-ruby/issues/857))
8
+
9
+ ### 0.15.0 (2022-11-17)
10
+
11
+ #### Features
12
+
13
+ * retry policy now works for REST calls
14
+
3
15
  ### 0.14.0 (2022-11-08)
4
16
 
5
17
  #### Features
@@ -0,0 +1,71 @@
1
+ # Copyright 2019 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Gapic
16
+ class CallOptions
17
+ ##
18
+ # @private
19
+ # The gRPC error codes and their HTTP mapping
20
+ #
21
+ module ErrorCodes
22
+ # @private
23
+ # See https://grpc.github.io/grpc/core/md_doc_statuscodes.html for a
24
+ # list of error codes.
25
+ error_code_mapping = [
26
+ "OK",
27
+ "CANCELLED",
28
+ "UNKNOWN",
29
+ "INVALID_ARGUMENT",
30
+ "DEADLINE_EXCEEDED",
31
+ "NOT_FOUND",
32
+ "ALREADY_EXISTS",
33
+ "PERMISSION_DENIED",
34
+ "RESOURCE_EXHAUSTED",
35
+ "FAILED_PRECONDITION",
36
+ "ABORTED",
37
+ "OUT_OF_RANGE",
38
+ "UNIMPLEMENTED",
39
+ "INTERNAL",
40
+ "UNAVAILABLE",
41
+ "DATA_LOSS",
42
+ "UNAUTHENTICATED"
43
+ ].freeze
44
+
45
+ # @private
46
+ ERROR_STRING_MAPPING = error_code_mapping.each_with_index.to_h.freeze
47
+
48
+ # @private
49
+ # Converts http error codes into corresponding gRPC ones
50
+ def self.grpc_error_for http_error_code
51
+ return 2 unless http_error_code
52
+
53
+ # The http status codes mapped to their error classes.
54
+ {
55
+ 400 => 3, # InvalidArgumentError
56
+ 401 => 16, # UnauthenticatedError
57
+ 403 => 7, # PermissionDeniedError
58
+ 404 => 5, # NotFoundError
59
+ 409 => 6, # AlreadyExistsError
60
+ 412 => 9, # FailedPreconditionError
61
+ 429 => 8, # ResourceExhaustedError
62
+ 499 => 1, # CanceledError
63
+ 500 => 13, # InternalError
64
+ 501 => 12, # UnimplementedError
65
+ 503 => 14, # UnavailableError
66
+ 504 => 4 # DeadlineExceededError
67
+ }[http_error_code] || 2 # UnknownError
68
+ end
69
+ end
70
+ end
71
+ end
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require "gapic/call_options/error_codes"
16
+
15
17
  module Gapic
16
18
  class CallOptions
17
19
  ##
@@ -101,38 +103,12 @@ module Gapic
101
103
  [retry_codes, initial_delay, multiplier, max_delay].hash
102
104
  end
103
105
 
104
- # @private
105
- # See https://grpc.github.io/grpc/core/md_doc_statuscodes.html for a
106
- # list of error codes.
107
- ERROR_CODE_MAPPING = [
108
- "OK",
109
- "CANCELLED",
110
- "UNKNOWN",
111
- "INVALID_ARGUMENT",
112
- "DEADLINE_EXCEEDED",
113
- "NOT_FOUND",
114
- "ALREADY_EXISTS",
115
- "PERMISSION_DENIED",
116
- "RESOURCE_EXHAUSTED",
117
- "FAILED_PRECONDITION",
118
- "ABORTED",
119
- "OUT_OF_RANGE",
120
- "UNIMPLEMENTED",
121
- "INTERNAL",
122
- "UNAVAILABLE",
123
- "DATA_LOSS",
124
- "UNAUTHENTICATED"
125
- ].freeze
126
-
127
- # @private
128
- ERROR_STRING_MAPPING = ERROR_CODE_MAPPING.each_with_index.each_with_object({}) do |(str, num), hash|
129
- hash[str] = num
130
- end.freeze
131
-
132
106
  private
133
107
 
134
108
  def retry? error
135
- error.is_a?(::GRPC::BadStatus) && retry_codes.include?(error.code)
109
+ (defined?(::GRPC) && error.is_a?(::GRPC::BadStatus) && retry_codes.include?(error.code)) ||
110
+ (error.respond_to?(:response_status) &&
111
+ retry_codes.include?(ErrorCodes.grpc_error_for(error.response_status)))
136
112
  end
137
113
 
138
114
  def delay!
@@ -145,7 +121,7 @@ module Gapic
145
121
  Array(input_codes).map do |obj|
146
122
  case obj
147
123
  when String
148
- ERROR_STRING_MAPPING[obj]
124
+ ErrorCodes::ERROR_STRING_MAPPING[obj]
149
125
  when Integer
150
126
  obj
151
127
  end
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require "gapic/call_options/error_codes"
15
16
  require "gapic/call_options/retry_policy"
16
17
 
17
18
  module Gapic
@@ -14,6 +14,6 @@
14
14
 
15
15
  module Gapic
16
16
  module Common
17
- VERSION = "0.14.0".freeze
17
+ VERSION = "0.15.1".freeze
18
18
  end
19
19
  end
@@ -125,21 +125,65 @@ module Gapic
125
125
  # @param uri [String] uri to send this request to
126
126
  # @param body [String, nil] a body to send with the request, nil for requests without a body
127
127
  # @param params [Hash] query string parameters for the request
128
- # @param options [::Gapic::CallOptions,Hash] gapic options to be applied
129
- # to the REST call. Currently only timeout and headers are supported.
128
+ # @param options [::Gapic::CallOptions,Hash] gapic options to be applied to the REST call.
129
+ # @param is_server_streaming [Boolean] flag if method is streaming
130
+ # @yieldparam chunk [String] The chunk of data received during server streaming.
131
+ # @return [Faraday::Response]
132
+ def make_http_request verb, uri:, body:, params:, options:, is_server_streaming: false, &block
133
+ # Converts hash and nil to an options object
134
+ options = ::Gapic::CallOptions.new(**options.to_h) unless options.is_a? ::Gapic::CallOptions
135
+ deadline = calculate_deadline options
136
+ retried_exception = nil
137
+ next_timeout = get_timeout deadline
138
+
139
+ begin
140
+ base_make_http_request(verb,
141
+ uri: uri,
142
+ body: body,
143
+ params: params,
144
+ metadata: options.metadata,
145
+ timeout: next_timeout,
146
+ is_server_streaming: is_server_streaming,
147
+ &block)
148
+ rescue ::Faraday::Error => e
149
+ next_timeout = get_timeout deadline
150
+
151
+ if next_timeout&.positive? && options.retry_policy.call(e)
152
+ retried_exception = e
153
+ retry
154
+ end
155
+
156
+ unless next_timeout&.positive?
157
+ raise Gapic::GRPC::DeadlineExceededError.new e.message, root_cause: retried_exception
158
+ end
159
+
160
+ raise e
161
+ end
162
+ end
163
+
164
+ private
165
+
166
+ ##
167
+ # @private
168
+ # Sends a http request via Faraday
169
+ # @param verb [Symbol] http verb
170
+ # @param uri [String] uri to send this request to
171
+ # @param body [String, nil] a body to send with the request, nil for requests without a body
172
+ # @param params [Hash] query string parameters for the request
173
+ # @param metadata [Hash] additional headers for the request
130
174
  # @param is_server_streaming [Boolean] flag if method is streaming
131
175
  # @yieldparam chunk [String] The chunk of data received during server streaming.
132
176
  # @return [Faraday::Response]
133
- def make_http_request verb, uri:, body:, params:, options:, is_server_streaming: false
177
+ def base_make_http_request verb, uri:, body:, params:, metadata:, timeout:, is_server_streaming: false
134
178
  if @numeric_enums && (!params.key?("$alt") || params["$alt"] == "json")
135
179
  params = params.merge({ "$alt" => "json;enum-encoding=int" })
136
180
  end
137
- options = ::Gapic::CallOptions.new(**options.to_h) unless options.is_a? ::Gapic::CallOptions
181
+
138
182
  @connection.send verb, uri do |req|
139
183
  req.params = params if params.any?
140
184
  req.body = body unless body.nil?
141
- req.headers = req.headers.merge options.metadata
142
- req.options.timeout = options.timeout if options.timeout&.positive?
185
+ req.headers = req.headers.merge metadata
186
+ req.options.timeout = timeout if timeout&.positive?
143
187
  if is_server_streaming
144
188
  req.options.on_data = proc do |chunk, _overall_received_bytes|
145
189
  yield chunk
@@ -147,6 +191,18 @@ module Gapic
147
191
  end
148
192
  end
149
193
  end
194
+
195
+ def calculate_deadline options
196
+ return if options.timeout.nil?
197
+ return if options.timeout.negative?
198
+
199
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) + options.timeout
200
+ end
201
+
202
+ def get_timeout deadline
203
+ return if deadline.nil?
204
+ deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
205
+ end
150
206
  end
151
207
  end
152
208
  end
@@ -15,6 +15,7 @@
15
15
  module Gapic
16
16
  module Rest
17
17
  class GrpcTranscoder
18
+ ##
18
19
  # @private
19
20
  # A single binding for GRPC-REST transcoding of a request
20
21
  # It includes a uri template with bound field parameters, a HTTP method type,
@@ -25,7 +26,8 @@ module Gapic
25
26
  # @attribute [r] template
26
27
  # @return [String] The URI template for the request.
27
28
  # @attribute [r] field_bindings
28
- # @return [Array<FieldBinding>] The field bindings for the URI template variables.
29
+ # @return [Array<Gapic::Rest::GrpcTranscoder::HttpBinding::FieldBinding>]
30
+ # The field bindings for the URI template variables.
29
31
  # @attribute [r] body
30
32
  # @return [String] The body template for the request.
31
33
  class HttpBinding
@@ -41,6 +43,57 @@ module Gapic
41
43
  @body = body
42
44
  end
43
45
 
46
+ ##
47
+ # @private
48
+ # Creates a new HttpBinding.
49
+ #
50
+ # @param uri_method [Symbol] The rest verb for the binding.
51
+ # @param uri_template [String] The string with uri template for the binding.
52
+ # This string will be expanded with the parameters from variable bindings.
53
+ # @param matches [Array<Array>] Variable bindings in an array. Every element
54
+ # of the array is an [Array] triplet, where:
55
+ # - the first element is a [String] field path (e.g. `foo.bar`) in the request
56
+ # to bind to
57
+ # - the second element is a [Regexp] to match the field value
58
+ # - the third element is a [Boolean] whether the slashes in the field value
59
+ # should be preserved (as opposed to escaped) when expanding the uri template.
60
+ # @param body [String, Nil] The body template, e.g. `*` or a field path.
61
+ #
62
+ # @return [Gapic::Rest::GrpcTranscoder::HttpBinding] The new binding.
63
+ def self.create_with_validation uri_method:, uri_template:, matches: [], body: nil
64
+ template = uri_template
65
+
66
+ matches.each do |name, _regex, _preserve_slashes|
67
+ unless uri_template =~ /({#{Regexp.quote name}})/
68
+ err_msg = "Binding configuration is incorrect: missing parameter in the URI template.\n" \
69
+ "Parameter `#{name}` is specified for matching but there is no corresponding parameter " \
70
+ "`{#{name}}` in the URI template."
71
+ raise ::Gapic::Common::Error, err_msg
72
+ end
73
+
74
+ template = template.gsub "{#{name}}", ""
75
+ end
76
+
77
+ if template =~ /{([a-zA-Z_.]+)}/
78
+ err_name = Regexp.last_match[1]
79
+ err_msg = "Binding configuration is incorrect: missing match configuration.\n" \
80
+ "Parameter `{#{err_name}}` is specified in the URI template but there is no " \
81
+ "corresponding match configuration for `#{err_name}`."
82
+ raise ::Gapic::Common::Error, err_msg
83
+ end
84
+
85
+ if body&.include? "."
86
+ raise ::Gapic::Common::Error,
87
+ "Provided body template `#{body}` points to a field in a sub-message. This is not supported."
88
+ end
89
+
90
+ field_bindings = matches.map do |name, regex, preserve_slashes|
91
+ HttpBinding::FieldBinding.new name, regex, preserve_slashes
92
+ end
93
+
94
+ HttpBinding.new uri_method, uri_template, field_bindings, body
95
+ end
96
+
44
97
  # A single binding for a field of a request message.
45
98
  # @attribute [r] field_path
46
99
  # @return [String] The path of the bound field, e.g. `foo.bar`.
@@ -44,36 +44,11 @@ module Gapic
44
44
  #
45
45
  # @return [Gapic::Rest::GrpcTranscoder] The updated transcoder.
46
46
  def with_bindings uri_method:, uri_template:, matches: [], body: nil
47
- template = uri_template
48
-
49
- matches.each do |name, _regex, _preserve_slashes|
50
- unless uri_template =~ /({#{Regexp.quote name}})/
51
- err_msg = "Binding configuration is incorrect: missing parameter in the URI template.\n" \
52
- "Parameter `#{name}` is specified for matching but there is no corresponding parameter " \
53
- "`{#{name}}` in the URI template."
54
- raise ::Gapic::Common::Error, err_msg
55
- end
56
-
57
- template = template.gsub "{#{name}}", ""
58
- end
59
-
60
- if template =~ /{([a-zA-Z_.]+)}/
61
- err_name = Regexp.last_match[1]
62
- err_msg = "Binding configuration is incorrect: missing match configuration.\n" \
63
- "Parameter `{#{err_name}}` is specified in the URI template but there is no " \
64
- "corresponding match configuration for `#{err_name}`."
65
- raise ::Gapic::Common::Error, err_msg
66
- end
67
-
68
- if body&.include? "."
69
- raise ::Gapic::Common::Error,
70
- "Provided body template `#{body}` points to a field in a sub-message. This is not supported."
71
- end
72
-
73
- field_bindings = matches.map do |name, regex, preserve_slashes|
74
- HttpBinding::FieldBinding.new name, regex, preserve_slashes
75
- end
76
- GrpcTranscoder.new @bindings + [HttpBinding.new(uri_method, uri_template, field_bindings, body)]
47
+ binding = HttpBinding.create_with_validation(uri_method: uri_method,
48
+ uri_template: uri_template,
49
+ matches: matches,
50
+ body: body)
51
+ GrpcTranscoder.new @bindings + [binding]
77
52
  end
78
53
 
79
54
  ##
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gapic-common
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Google API Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-08 00:00:00.000000000 Z
11
+ date: 2022-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -288,6 +288,7 @@ files:
288
288
  - RELEASING.md
289
289
  - lib/gapic-common.rb
290
290
  - lib/gapic/call_options.rb
291
+ - lib/gapic/call_options/error_codes.rb
291
292
  - lib/gapic/call_options/retry_policy.rb
292
293
  - lib/gapic/common.rb
293
294
  - lib/gapic/common/error.rb