my_api_client 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dependabot/config.yml +2 -5
- data/CHANGELOG.md +60 -0
- data/Gemfile.lock +8 -8
- data/README.jp.md +34 -21
- data/example/api_clients/application_api_client.rb +0 -8
- data/lib/generators/rails/templates/application_api_client.rb.erb +0 -11
- data/lib/my_api_client.rb +5 -0
- data/lib/my_api_client/base.rb +2 -0
- data/lib/my_api_client/default_error_handlers.rb +64 -0
- data/lib/my_api_client/error_handling.rb +3 -4
- data/lib/my_api_client/error_handling/generator.rb +23 -5
- data/lib/my_api_client/errors.rb +0 -53
- data/lib/my_api_client/errors/api_limit_error.rb +6 -0
- data/lib/my_api_client/errors/client_error.rb +93 -0
- data/lib/my_api_client/errors/network_error.rb +43 -0
- data/lib/my_api_client/errors/server_error.rb +42 -0
- data/lib/my_api_client/version.rb +1 -1
- data/my_api/Gemfile.lock +3 -3
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81476ec85e1664e0b1109e44ea2c5b29eaf110954e687712826886d5e986b06f
|
4
|
+
data.tar.gz: 226c07c69e767db0863449d66585b2c1c42ececb529a727147e14e5fe70049db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '009f14b37302243f4063703f8d5dd41680e6821b013e935165e9110c680b5b98cca9317d5e3abac8fade76f6fb0ba07aac0edad3bfb2b441e4a86f7e95e14534'
|
7
|
+
data.tar.gz: b718464bb2245c646692f2b0e5ce2dcbac6e7f15f2d4b88b7c5393c097116ed627f59371f9a75a51fdbebedf773c3de73780a92334214b725ebe3373ba72d6f1
|
data/.dependabot/config.yml
CHANGED
@@ -2,16 +2,13 @@ version: 1
|
|
2
2
|
update_configs:
|
3
3
|
- package_manager: "ruby:bundler"
|
4
4
|
directory: "/"
|
5
|
-
update_schedule: "
|
5
|
+
update_schedule: "live"
|
6
6
|
default_reviewers:
|
7
7
|
- "ryz310"
|
8
8
|
default_assignees:
|
9
9
|
- "ryz310"
|
10
10
|
default_labels:
|
11
11
|
- "dependabot"
|
12
|
-
ignored_updates:
|
13
|
-
- match:
|
14
|
-
dependency_name: "rubocop*"
|
15
12
|
automerged_updates:
|
16
13
|
- match:
|
17
14
|
dependency_type: "development"
|
@@ -21,7 +18,7 @@ update_configs:
|
|
21
18
|
update_type: "semver:patch"
|
22
19
|
- package_manager: "ruby:bundler"
|
23
20
|
directory: "/my_api"
|
24
|
-
update_schedule: "
|
21
|
+
update_schedule: "live"
|
25
22
|
default_reviewers:
|
26
23
|
- "ryz310"
|
27
24
|
default_assignees:
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,65 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## v0.16.0 (Mar 29, 2020)
|
4
|
+
|
5
|
+
### Breaking Change
|
6
|
+
|
7
|
+
#### [#225](https://github.com/ryz310/my_api_client/pull/225) Raise an exception whenever an error is detected ([@ryz310](https://github.com/ryz310))
|
8
|
+
|
9
|
+
Until now, using `with` or `block` in `error_handling` did not automatically raise an exception, but will now always raise an exception when an error is detected.
|
10
|
+
You can specify raising error class with `raise` option.
|
11
|
+
|
12
|
+
**Before**
|
13
|
+
|
14
|
+
```rb
|
15
|
+
error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
16
|
+
|
17
|
+
def my_error_handling
|
18
|
+
# Executes this method when an error is detected.
|
19
|
+
# No exception is raised. You can raise an error if necessary.
|
20
|
+
end
|
21
|
+
```
|
22
|
+
```rb
|
23
|
+
error_handling status_code: 500..599 do |_params, logger|
|
24
|
+
# Executes this block when an error is detected.
|
25
|
+
# No exception is raised. You can raise an error if necessary.
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
**After**
|
30
|
+
|
31
|
+
```rb
|
32
|
+
error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
33
|
+
|
34
|
+
def my_error_handling
|
35
|
+
# Executes this method when an error is detected.
|
36
|
+
# And then raise `MyApiClient::Error`.
|
37
|
+
end
|
38
|
+
```
|
39
|
+
```rb
|
40
|
+
error_handling status_code: 500..599 do |params, logger|
|
41
|
+
# Executes this block when an error is detected.
|
42
|
+
# And then raise `MyApiClient::Error`.
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
#### [#226](https://github.com/ryz310/my_api_client/pull/226) Default error handlers ([@ryz310](https://github.com/ryz310))
|
47
|
+
|
48
|
+
Until now, you needed define all `error_handling` or `retry_on` yourself. But will now some `error_handling` and `retry_on` are prepared as default.
|
49
|
+
|
50
|
+
You can check default `error_handling` or `retry_on` here.
|
51
|
+
|
52
|
+
See: https://github.com/ryz310/my_api_client/blob/master/lib/my_api_client/default_error_handlers.rb
|
53
|
+
|
54
|
+
### Dependabot
|
55
|
+
|
56
|
+
* [#227](https://github.com/ryz310/my_api_client/pull/227) ryz310/dependabot/bundler/pry-byebug-3.9.0 ([@ryz310](https://github.com/ryz310))
|
57
|
+
* [#228](https://github.com/ryz310/my_api_client/pull/228) ryz310/dependabot/bundler/my_api/jets-2.3.15 ([@ryz310](https://github.com/ryz310))
|
58
|
+
|
59
|
+
### Misc
|
60
|
+
|
61
|
+
* [#229](https://github.com/ryz310/my_api_client/pull/229) Edit dependabot configuration ([@ryz310](https://github.com/ryz310))
|
62
|
+
|
3
63
|
## v0.15.0 (Mar 21, 2020)
|
4
64
|
|
5
65
|
### 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.16.0)
|
5
5
|
activesupport (>= 4.2.0)
|
6
6
|
faraday (>= 0.17.1)
|
7
7
|
jsonpath
|
@@ -37,19 +37,19 @@ GEM
|
|
37
37
|
jsonpath (1.0.5)
|
38
38
|
multi_json
|
39
39
|
to_regexp (~> 0.2.1)
|
40
|
-
method_source (0.
|
40
|
+
method_source (1.0.0)
|
41
41
|
minitest (5.14.0)
|
42
42
|
multi_json (1.14.1)
|
43
43
|
multipart-post (2.1.1)
|
44
44
|
parallel (1.19.1)
|
45
|
-
parser (2.7.0.
|
45
|
+
parser (2.7.0.5)
|
46
46
|
ast (~> 2.4.0)
|
47
|
-
pry (0.
|
48
|
-
coderay (~> 1.1
|
49
|
-
method_source (~>
|
50
|
-
pry-byebug (3.
|
47
|
+
pry (0.13.0)
|
48
|
+
coderay (~> 1.1)
|
49
|
+
method_source (~> 1.0)
|
50
|
+
pry-byebug (3.9.0)
|
51
51
|
byebug (~> 11.0)
|
52
|
-
pry (~> 0.
|
52
|
+
pry (~> 0.13.0)
|
53
53
|
public_suffix (4.0.3)
|
54
54
|
rainbow (3.0.0)
|
55
55
|
rake (13.0.1)
|
data/README.jp.md
CHANGED
@@ -6,7 +6,9 @@ MyApiClient は API リクエストクラスを作成するための汎用的な
|
|
6
6
|
|
7
7
|
ただし、 Sawyer はダミーデータの作成が難しかったり、他の gem で競合することがよくあるので、将来的には依存しないように変更していくかもしれません。
|
8
8
|
|
9
|
-
また、 Ruby on Rails
|
9
|
+
また、 Ruby on Rails で利用することを想定してますが、それ以外の環境でも動作するように作っています。不具合などあれば Issue ページからご報告下さい。
|
10
|
+
|
11
|
+
[toc]
|
10
12
|
|
11
13
|
## Supported Versions
|
12
14
|
|
@@ -147,30 +149,31 @@ end
|
|
147
149
|
|
148
150
|
### Error handling
|
149
151
|
|
150
|
-
|
152
|
+
`my_api_client` ではレスポンスの内容によって例外を発生させるエラーハンドリングを定義できます。ここでは例として前述のコードにエラーハンドリングを定義しています。
|
151
153
|
|
152
154
|
```ruby
|
153
155
|
class ExampleApiClient < MyApiClient::Base
|
154
156
|
endpoint 'https://example.com'
|
155
157
|
|
156
|
-
error_handling status_code: 400..499,
|
158
|
+
error_handling status_code: 400..499,
|
159
|
+
raise: MyApiClient::ClientError
|
157
160
|
|
158
|
-
error_handling status_code: 500..599 do |
|
161
|
+
error_handling status_code: 500..599, raise: MyApiClient::ServerError do |_params, logger|
|
159
162
|
logger.warn 'Server error occurred.'
|
160
|
-
raise MyApiClient::ServerError, params
|
161
163
|
end
|
162
164
|
|
163
|
-
error_handling json: { '$.errors.code': 10..19 },
|
165
|
+
error_handling json: { '$.errors.code': 10..19 },
|
166
|
+
raise: MyApiClient::ClientError,
|
167
|
+
with: :my_error_handling
|
164
168
|
|
165
169
|
# Omission...
|
166
170
|
|
167
171
|
private
|
168
172
|
|
169
|
-
# @param params [MyApiClient::Params::Params] HTTP
|
173
|
+
# @param params [MyApiClient::Params::Params] HTTP reqest and response params
|
170
174
|
# @param logger [MyApiClient::Request::Logger] Logger for a request processing
|
171
175
|
def my_error_handling(params, logger)
|
172
176
|
logger.warn "Response Body: #{params.response.body.inspect}"
|
173
|
-
raise MyApiClient::ClientError, params
|
174
177
|
end
|
175
178
|
end
|
176
179
|
```
|
@@ -183,29 +186,26 @@ error_handling status_code: 400..499, raise: MyApiClient::ClientError
|
|
183
186
|
|
184
187
|
これは `ExampleApiClient` からのリクエスト全てにおいて、レスポンスのステータスコードが `400..499` であった場合に `MyApiClient::ClientError` が例外として発生するようになります。 `ExampleApiClient` を継承したクラスにもエラーハンドリングは適用されます。ステータスコードのエラーハンドリングは親クラスで定義すると良いと思います。
|
185
188
|
|
186
|
-
なお、 `status_code` には `Integer` `Range` `Regexp`
|
189
|
+
なお、 `status_code` には `Integer` `Range` `Regexp` が指定可能です。
|
190
|
+
|
191
|
+
`raise` には `MyApiClient::Error` を継承したクラスが指定可能です。`my_api_client` で標準で定義しているエラークラスについては以下のソースコードをご確認下さい。 `raise` を省略した場合は `MyApiClient::Error` を発生するようになります。
|
187
192
|
|
188
|
-
https://github.com/ryz310/my_api_client/blob/master/lib/my_api_client/errors
|
193
|
+
https://github.com/ryz310/my_api_client/blob/master/lib/my_api_client/errors
|
189
194
|
|
190
|
-
次に、 `
|
195
|
+
次に、 `block` を指定する場合について。
|
191
196
|
|
192
197
|
```ruby
|
193
|
-
error_handling status_code: 500..599 do |
|
198
|
+
error_handling status_code: 500..599, raise: MyApiClient::ServerError do |_params, logger|
|
194
199
|
logger.warn 'Server error occurred.'
|
195
|
-
raise MyApiClient::ServerError, params
|
196
200
|
end
|
197
201
|
```
|
198
202
|
|
199
|
-
上記の例であれば、ステータスコードが `500..599` の場合に `block` の内容が実行れます。引数の `params` にはリクエスト情報とレスポンス情報が含まれています。`logger` はログ出力用インスタンスですが、このインスタンスを使ってログ出力すると、以下のようにリクエスト情報がログ出力に含まれるようになり、デバッグの際に便利です。
|
203
|
+
上記の例であれば、ステータスコードが `500..599` の場合に `MyApiClient::ServerError` を発生させる前に `block` の内容が実行れます。引数の `params` にはリクエスト情報とレスポンス情報が含まれています。`logger` はログ出力用インスタンスですが、このインスタンスを使ってログ出力すると、以下のようにリクエスト情報がログ出力に含まれるようになり、デバッグの際に便利です。
|
200
204
|
|
201
205
|
```text
|
202
206
|
API request `GET https://example.com/path/to/resouce`: "Server error occurred."
|
203
207
|
```
|
204
208
|
|
205
|
-
リクエストに失敗した場合は例外処理を実行する、という設計が一般的だと思われるので、基本的にブロックの最後に `raise` を実行する事になると思います。
|
206
|
-
|
207
|
-
最後に `json` と `with` を利用する場合について。
|
208
|
-
|
209
209
|
```ruby
|
210
210
|
error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
211
211
|
```
|
@@ -221,17 +221,28 @@ error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
|
221
221
|
}
|
222
222
|
```
|
223
223
|
|
224
|
-
`with`
|
224
|
+
`with` にはインスタンスメソッド名を指定することで、エラーを検出した際、例外を発生させる前に任意のメソッドを実行させることができます。メソッドに渡される引数は `block` 定義の場合と同じく `params` と `logger` です。なお、 `block` と `with` は同時には利用できません。
|
225
225
|
|
226
226
|
```ruby
|
227
227
|
# @param params [MyApiClient::Params::Params] HTTP req and res params
|
228
228
|
# @param logger [MyApiClient::Request::Logger] Logger for a request processing
|
229
229
|
def my_error_handling(params, logger)
|
230
230
|
logger.warn "Response Body: #{params.response.body.inspect}"
|
231
|
-
raise MyApiClient::ClientError, params
|
232
231
|
end
|
233
232
|
```
|
234
233
|
|
234
|
+
#### Default error handling
|
235
|
+
|
236
|
+
`my_api_client` では、標準でステータスコード 400 ~ 500 番台のレスポンスを例外として処理するようにしています。ステータスコードが 400 番台場合は `MyApiClient::ClientError`、 500 番台の場合は `MyApiClient::ServerError` を継承した例外クラスが raise されます。
|
237
|
+
|
238
|
+
また、 `MyApiClient::NetworkError` に対しても標準で `retry_on` が定義されています。
|
239
|
+
|
240
|
+
いずれも override 可能ですので、必要に応じて `error_handling` を定義して下さい。
|
241
|
+
|
242
|
+
以下のファイルで定義しています。
|
243
|
+
|
244
|
+
https://github.com/ryz310/my_api_client/blob/master/lib/my_api_client/default_error_handlers.rb
|
245
|
+
|
235
246
|
#### Symbol を利用する
|
236
247
|
|
237
248
|
```ruby
|
@@ -300,7 +311,9 @@ end
|
|
300
311
|
|
301
312
|
API リクエストを何度も実行していると回線の不調などによりネットワークエラーが発生する事があります。長時間ネットワークが使えなくなるケースもありますが、瞬間的なエラーであるケースも多々あります。 `MyApiClient` ではネットワーク系の例外はまとめて `MyApiClient::NetworkError` として `raise` されます。この例外の詳細は後述しますが、 `retry_on` を利用する事で、 `ActiveJob` のように任意の例外処理を補足して、一定回数、一定の期間を空けて API リクエストをリトライさせる事ができます。
|
302
313
|
|
303
|
-
|
314
|
+
なお、 `retry_on MyApiClient::NetworkError` は標準実装されているため、特別に定義せずとも自動的に適用されます。 `wait` や `attempts` に任意の値を設定したい場合のみ定義してご利用ください。
|
315
|
+
|
316
|
+
ただし、 `ActiveJob` とは異なり同期処理でリトライするため、ネットワークの瞬断に備えたリトライ以外ではあまり使う機会はないのではないかと思います。上記の例のように API Rate Limit に備えてリトライするケースもあるかと思いますが、こちらは `ActiveJob` で対応した方が良いかもしれません。
|
304
317
|
|
305
318
|
ちなみに一応 `discard_on` も実装していますが、作者自身が有効な用途を見出せていないので、詳細は割愛します。良い利用方法があれば教えてください。
|
306
319
|
|
@@ -10,12 +10,4 @@ class ApplicationApiClient < MyApiClient::Base
|
|
10
10
|
|
11
11
|
http_open_timeout 2.seconds
|
12
12
|
http_read_timeout 3.seconds
|
13
|
-
|
14
|
-
retry_on MyApiClient::NetworkError, wait: 0.seconds, attempts: 3
|
15
|
-
|
16
|
-
error_handling status_code: 400..499, raise: MyApiClient::ClientError
|
17
|
-
error_handling status_code: 500..599 do |params, logger|
|
18
|
-
logger.warn 'Server error occurred.'
|
19
|
-
raise MyApiClient::ServerError, params
|
20
|
-
end
|
21
13
|
end
|
@@ -20,15 +20,4 @@ class ApplicationApiClient < MyApiClient::Base
|
|
20
20
|
# seconds.
|
21
21
|
#
|
22
22
|
# http_read_timeout 3.seconds
|
23
|
-
|
24
|
-
# Catch the exception and re-execution after any seconds, like as ActiveJob.
|
25
|
-
# Please note that it is executed as a synchronous process unlike ActiveJob.
|
26
|
-
#
|
27
|
-
# retry_on MyApiClient::NetworkError, wait: 5.seconds, attempts: 3
|
28
|
-
|
29
|
-
# Set a HTTP response verifyment and behavior. If conflicting conditions are
|
30
|
-
# set, the processing defined later takes precedence
|
31
|
-
#
|
32
|
-
# error_handling status_code: 400..499, raise: MyApiClient::ClientError
|
33
|
-
# error_handling status_code: 500..599, raise: MyApiClient::ServerError
|
34
23
|
end
|
data/lib/my_api_client.rb
CHANGED
@@ -19,6 +19,11 @@ require 'my_api_client/request/executor'
|
|
19
19
|
require 'my_api_client/request/basic'
|
20
20
|
require 'my_api_client/request/pagination'
|
21
21
|
require 'my_api_client/errors'
|
22
|
+
require 'my_api_client/errors/api_limit_error'
|
23
|
+
require 'my_api_client/errors/client_error'
|
24
|
+
require 'my_api_client/errors/network_error'
|
25
|
+
require 'my_api_client/errors/server_error'
|
26
|
+
require 'my_api_client/default_error_handlers'
|
22
27
|
require 'my_api_client/params/params'
|
23
28
|
require 'my_api_client/params/request'
|
24
29
|
require 'my_api_client/request'
|
data/lib/my_api_client/base.rb
CHANGED
@@ -18,6 +18,8 @@ module MyApiClient
|
|
18
18
|
self.error_handlers = []
|
19
19
|
end
|
20
20
|
|
21
|
+
include MyApiClient::DefaultErrorHandlers
|
22
|
+
|
21
23
|
# NOTE: This class **MUST NOT** implement #initialize method. Because it
|
22
24
|
# will become constraint that need call #super in the #initialize at
|
23
25
|
# definition of the child classes.
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
# Provides default error handlers.
|
5
|
+
module DefaultErrorHandlers
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# rubocop:disable Metrics/BlockLength
|
9
|
+
included do
|
10
|
+
# NOTE: The built-in error handlers are following. Although they are prepared
|
11
|
+
# to save the trouble of defining, but you can override any error handlers
|
12
|
+
# in your API client class.
|
13
|
+
error_handling status_code: 400..499, raise: ClientError
|
14
|
+
error_handling status_code: 400, raise: ClientError::BadRequest
|
15
|
+
error_handling status_code: 401, raise: ClientError::Unauthorized
|
16
|
+
error_handling status_code: 402, raise: ClientError::PaymentRequired
|
17
|
+
error_handling status_code: 403, raise: ClientError::Forbidden
|
18
|
+
error_handling status_code: 404, raise: ClientError::NotFound
|
19
|
+
error_handling status_code: 405, raise: ClientError::MethodNotAllowed
|
20
|
+
error_handling status_code: 406, raise: ClientError::NotAcceptable
|
21
|
+
error_handling status_code: 407, raise: ClientError::ProxyAuthenticationRequired
|
22
|
+
error_handling status_code: 408, raise: ClientError::RequestTimeout
|
23
|
+
error_handling status_code: 409, raise: ClientError::Conflict
|
24
|
+
error_handling status_code: 410, raise: ClientError::Gone
|
25
|
+
error_handling status_code: 411, raise: ClientError::LengthRequired
|
26
|
+
error_handling status_code: 412, raise: ClientError::PreconditionFailed
|
27
|
+
error_handling status_code: 413, raise: ClientError::RequestEntityTooLarge
|
28
|
+
error_handling status_code: 414, raise: ClientError::RequestUriTooLong
|
29
|
+
error_handling status_code: 415, raise: ClientError::UnsupportedMediaType
|
30
|
+
error_handling status_code: 416, raise: ClientError::RequestedRangeNotSatisfiable
|
31
|
+
error_handling status_code: 417, raise: ClientError::ExpectationFailed
|
32
|
+
error_handling status_code: 418, raise: ClientError::IamTeapot
|
33
|
+
error_handling status_code: 421, raise: ClientError::MisdirectedRequest
|
34
|
+
error_handling status_code: 422, raise: ClientError::UnprocessableEntity
|
35
|
+
error_handling status_code: 423, raise: ClientError::Locked
|
36
|
+
error_handling status_code: 424, raise: ClientError::FailedDependency
|
37
|
+
error_handling status_code: 425, raise: ClientError::TooEarly
|
38
|
+
error_handling status_code: 426, raise: ClientError::UpgradeRequired
|
39
|
+
error_handling status_code: 428, raise: ClientError::PreconditionRequired
|
40
|
+
error_handling status_code: 429, raise: ClientError::TooManyRequests
|
41
|
+
error_handling status_code: 431, raise: ClientError::RequestHeaderFieldsTooLarge
|
42
|
+
error_handling status_code: 451, raise: ClientError::UnavailableForLegalReasons
|
43
|
+
|
44
|
+
error_handling status_code: 500..599, raise: ServerError
|
45
|
+
error_handling status_code: 500, raise: ServerError::InternalServerError
|
46
|
+
error_handling status_code: 501, raise: ServerError::NotImplemented
|
47
|
+
error_handling status_code: 502, raise: ServerError::BadGateway
|
48
|
+
error_handling status_code: 503, raise: ServerError::ServiceUnavailable
|
49
|
+
error_handling status_code: 504, raise: ServerError::GatewayTimeout
|
50
|
+
error_handling status_code: 505, raise: ServerError::HttpVersionNotSupported
|
51
|
+
error_handling status_code: 506, raise: ServerError::VariantAlsoNegotiates
|
52
|
+
error_handling status_code: 507, raise: ServerError::InsufficientStorage
|
53
|
+
error_handling status_code: 508, raise: ServerError::LoopDetected
|
54
|
+
error_handling status_code: 509, raise: ServerError::BandwidthLimitExceeded
|
55
|
+
error_handling status_code: 510, raise: ServerError::NotExtended
|
56
|
+
error_handling status_code: 511, raise: ServerError::NetworkAuthenticationRequired
|
57
|
+
|
58
|
+
# Catch the exception and re-execution after any seconds, like as ActiveJob.
|
59
|
+
# Please note that it is executed as a synchronous process unlike ActiveJob.
|
60
|
+
retry_on NetworkError, wait: 0.3.seconds, attempts: 3
|
61
|
+
end
|
62
|
+
# rubocop:enable Metrics/BlockLength
|
63
|
+
end
|
64
|
+
end
|
@@ -9,9 +9,8 @@ module MyApiClient
|
|
9
9
|
# @example
|
10
10
|
# error_handling status_code: 200, json: :forbid_nil
|
11
11
|
# error_handling status_code: 400..499, raise: MyApiClient::ClientError
|
12
|
-
# error_handling status_code: 500..599 do |params, logger|
|
12
|
+
# error_handling status_code: 500..599, raise: MyApiClient::ServerError do |params, logger|
|
13
13
|
# logger.warn 'Server error occurred.'
|
14
|
-
# raise MyApiClient::ServerError, params
|
15
14
|
# end
|
16
15
|
#
|
17
16
|
# error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
@@ -33,7 +32,7 @@ module MyApiClient
|
|
33
32
|
# as JsonPath expression.
|
34
33
|
# If specified `:forbid_nil`, it forbid `nil` at the response body.
|
35
34
|
# @option with [Symbol]
|
36
|
-
# Calls specified method when error detected
|
35
|
+
# Calls specified method before raising exception when error detected.
|
37
36
|
# @option raise [MyApiClient::Error]
|
38
37
|
# Raises specified error when an invalid response detected.
|
39
38
|
# Should be inherited `MyApiClient::Error` class.
|
@@ -42,7 +41,7 @@ module MyApiClient
|
|
42
41
|
# If the error detected, retries the API request. Requires `raise` option.
|
43
42
|
# You can set `true` or `retry_on` options (`wait` and `attempts`).
|
44
43
|
# @yield [MyApiClient::Params::Params, MyApiClient::Request::Logger]
|
45
|
-
# Executes the block when error detected.
|
44
|
+
# Executes the block before raising exception when error detected.
|
46
45
|
# Forbid to be used with the` retry` option.
|
47
46
|
def error_handling(**options, &block)
|
48
47
|
options[:block] = block
|
@@ -23,8 +23,8 @@ module MyApiClient
|
|
23
23
|
# Raises specified error when error detected. default: MyApiClient::Error
|
24
24
|
# @option block [Proc]
|
25
25
|
# Executes the block when error detected
|
26
|
-
# @return [Proc]
|
27
|
-
# Returns
|
26
|
+
# @return [Proc, nil]
|
27
|
+
# Returns the error handler as "Proc". If no error occurs, return `nil`.
|
28
28
|
def initialize(**options)
|
29
29
|
options[:raise] ||= MyApiClient::Error
|
30
30
|
verify_and_set_arguments(**options)
|
@@ -43,14 +43,32 @@ module MyApiClient
|
|
43
43
|
|
44
44
|
def generate_error_handler
|
45
45
|
if _block
|
46
|
-
|
46
|
+
block_caller
|
47
47
|
elsif _with
|
48
|
-
|
48
|
+
method_caller
|
49
49
|
else
|
50
|
-
|
50
|
+
error_raiser
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
def block_caller
|
55
|
+
lambda { |params, logger|
|
56
|
+
_block.call(params, logger)
|
57
|
+
error_raiser.call(params, logger)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def method_caller
|
62
|
+
lambda { |params, logger|
|
63
|
+
_instance.send(_with, params, logger)
|
64
|
+
error_raiser.call(params, logger)
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def error_raiser
|
69
|
+
->(params, _) { raise _raise, params }
|
70
|
+
end
|
71
|
+
|
54
72
|
# Verify given options and raise error if they are incorrect.
|
55
73
|
# If not, set them to instance variables.
|
56
74
|
#
|
data/lib/my_api_client/errors.rb
CHANGED
@@ -25,57 +25,4 @@ module MyApiClient
|
|
25
25
|
{ error: super, params: params }.inspect
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
29
|
-
NETWORK_ERRORS = [
|
30
|
-
Faraday::TimeoutError,
|
31
|
-
Faraday::ConnectionFailed,
|
32
|
-
Faraday::SSLError,
|
33
|
-
OpenSSL::SSL::SSLError,
|
34
|
-
Net::OpenTimeout,
|
35
|
-
Net::ReadTimeout,
|
36
|
-
SocketError,
|
37
|
-
].freeze
|
38
|
-
|
39
|
-
# Raises it when occurred to some network error
|
40
|
-
class NetworkError < Error
|
41
|
-
attr_reader :original_error
|
42
|
-
|
43
|
-
# Initialize the error class
|
44
|
-
#
|
45
|
-
# @param params [MyApiClient::Params::Params]
|
46
|
-
# The request and response parameters
|
47
|
-
# @param original_error [StandardError]
|
48
|
-
# Some network error
|
49
|
-
def initialize(params, original_error)
|
50
|
-
@original_error = original_error
|
51
|
-
super params, original_error.message
|
52
|
-
end
|
53
|
-
|
54
|
-
# Returns contents as string for to be readable for human
|
55
|
-
#
|
56
|
-
# @return [String] Contents as string
|
57
|
-
def inspect
|
58
|
-
{ error: original_error, params: params }.inspect
|
59
|
-
end
|
60
|
-
|
61
|
-
# Generate metadata for bugsnag.
|
62
|
-
#
|
63
|
-
# @return [Hash] Metadata for bugsnag
|
64
|
-
def metadata
|
65
|
-
super.merge(original_error: original_error.inspect)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# NOTE: The built-in error classes are following. Although they are prepared
|
70
|
-
# to save the trouble of defining, but you can create any error classes
|
71
|
-
# which inherit the ancestor error class.
|
72
|
-
|
73
|
-
# For 4xx client error
|
74
|
-
class ClientError < Error; end
|
75
|
-
|
76
|
-
# For 5xx server error
|
77
|
-
class ServerError < Error; end
|
78
|
-
|
79
|
-
# For API request limit error
|
80
|
-
class ApiLimitError < Error; end
|
81
28
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
# For 4xx client error
|
5
|
+
class ClientError < Error
|
6
|
+
# 400 Bad Request
|
7
|
+
class BadRequest < ClientError; end
|
8
|
+
|
9
|
+
# 401 Unauthorized
|
10
|
+
class Unauthorized < ClientError; end
|
11
|
+
|
12
|
+
# 402 Payment Required
|
13
|
+
class PaymentRequired < ClientError; end
|
14
|
+
|
15
|
+
# 403 Forbidden
|
16
|
+
class Forbidden < ClientError; end
|
17
|
+
|
18
|
+
# 404 Not Found
|
19
|
+
class NotFound < ClientError; end
|
20
|
+
|
21
|
+
# 405 Method Not Allowed
|
22
|
+
class MethodNotAllowed < ClientError; end
|
23
|
+
|
24
|
+
# 406 Not Acceptable
|
25
|
+
class NotAcceptable < ClientError; end
|
26
|
+
|
27
|
+
# 407 Proxy Authentication Required
|
28
|
+
class ProxyAuthenticationRequired < ClientError; end
|
29
|
+
|
30
|
+
# 408 Request Timeout
|
31
|
+
class RequestTimeout < ClientError; end
|
32
|
+
|
33
|
+
# 409 Conflict
|
34
|
+
class Conflict < ClientError; end
|
35
|
+
|
36
|
+
# 410 Gone
|
37
|
+
class Gone < ClientError; end
|
38
|
+
|
39
|
+
# 411 Length Required
|
40
|
+
class LengthRequired < ClientError; end
|
41
|
+
|
42
|
+
# 412 Precondition Failed
|
43
|
+
class PreconditionFailed < ClientError; end
|
44
|
+
|
45
|
+
# 413 Payload Too Large
|
46
|
+
class RequestEntityTooLarge < ClientError; end
|
47
|
+
|
48
|
+
# 414 URI Too Long
|
49
|
+
class RequestUriTooLong < ClientError; end
|
50
|
+
|
51
|
+
# 415 Unsupported Media Type
|
52
|
+
class UnsupportedMediaType < ClientError; end
|
53
|
+
|
54
|
+
# 416 Range Not Satisfiable
|
55
|
+
class RequestedRangeNotSatisfiable < ClientError; end
|
56
|
+
|
57
|
+
# 417 Expectation Failed
|
58
|
+
class ExpectationFailed < ClientError; end
|
59
|
+
|
60
|
+
# 418 I'm a teapot
|
61
|
+
class IamTeapot < ClientError; end
|
62
|
+
|
63
|
+
# 421 Misdirected Request
|
64
|
+
class MisdirectedRequest < ClientError; end
|
65
|
+
|
66
|
+
# 422 Unprocessable Entity
|
67
|
+
class UnprocessableEntity < ClientError; end
|
68
|
+
|
69
|
+
# 423 Locked
|
70
|
+
class Locked < ClientError; end
|
71
|
+
|
72
|
+
# 424 Failed Dependency
|
73
|
+
class FailedDependency < ClientError; end
|
74
|
+
|
75
|
+
# 425 Too Early
|
76
|
+
class TooEarly < ClientError; end
|
77
|
+
|
78
|
+
# 426 Upgrade Required
|
79
|
+
class UpgradeRequired < ClientError; end
|
80
|
+
|
81
|
+
# 428 Precondition Required
|
82
|
+
class PreconditionRequired < ClientError; end
|
83
|
+
|
84
|
+
# 429 Too Many Requests
|
85
|
+
class TooManyRequests < ClientError; end
|
86
|
+
|
87
|
+
# 431 Request Header Fields Too Large
|
88
|
+
class RequestHeaderFieldsTooLarge < ClientError; end
|
89
|
+
|
90
|
+
# 451 Unavailable for Legal Reasons
|
91
|
+
class UnavailableForLegalReasons < ClientError; end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
NETWORK_ERRORS = [
|
5
|
+
Faraday::TimeoutError,
|
6
|
+
Faraday::ConnectionFailed,
|
7
|
+
Faraday::SSLError,
|
8
|
+
OpenSSL::SSL::SSLError,
|
9
|
+
Net::OpenTimeout,
|
10
|
+
Net::ReadTimeout,
|
11
|
+
SocketError,
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
# Raises it when occurred to some network error
|
15
|
+
class NetworkError < Error
|
16
|
+
attr_reader :original_error
|
17
|
+
|
18
|
+
# Initialize the error class
|
19
|
+
#
|
20
|
+
# @param params [MyApiClient::Params::Params]
|
21
|
+
# The request and response parameters
|
22
|
+
# @param original_error [StandardError]
|
23
|
+
# Some network error
|
24
|
+
def initialize(params, original_error)
|
25
|
+
@original_error = original_error
|
26
|
+
super params, original_error.message
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns contents as string for to be readable for human
|
30
|
+
#
|
31
|
+
# @return [String] Contents as string
|
32
|
+
def inspect
|
33
|
+
{ error: original_error, params: params }.inspect
|
34
|
+
end
|
35
|
+
|
36
|
+
# Generate metadata for bugsnag.
|
37
|
+
#
|
38
|
+
# @return [Hash] Metadata for bugsnag
|
39
|
+
def metadata
|
40
|
+
super.merge(original_error: original_error.inspect)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
# For 5xx server error
|
5
|
+
class ServerError < Error
|
6
|
+
# 500 Internal Server Error
|
7
|
+
class InternalServerError < ServerError; end
|
8
|
+
|
9
|
+
# 501 Not Implemented
|
10
|
+
class NotImplemented < ServerError; end
|
11
|
+
|
12
|
+
# 502 Bad Gateway
|
13
|
+
class BadGateway < ServerError; end
|
14
|
+
|
15
|
+
# 503 Service Unavailable
|
16
|
+
class ServiceUnavailable < ServerError; end
|
17
|
+
|
18
|
+
# 504 Gateway Timeout
|
19
|
+
class GatewayTimeout < ServerError; end
|
20
|
+
|
21
|
+
# 505 HTTP Version Not Supported
|
22
|
+
class HttpVersionNotSupported < ServerError; end
|
23
|
+
|
24
|
+
# 506 Variant Also Negotiates
|
25
|
+
class VariantAlsoNegotiates < ServerError; end
|
26
|
+
|
27
|
+
# 507 Insufficient Storage
|
28
|
+
class InsufficientStorage < ServerError; end
|
29
|
+
|
30
|
+
# 508 Loop Detected
|
31
|
+
class LoopDetected < ServerError; end
|
32
|
+
|
33
|
+
# 509 Bandwidth Limit Exceeded
|
34
|
+
class BandwidthLimitExceeded < ServerError; end
|
35
|
+
|
36
|
+
# 510 Not Extended
|
37
|
+
class NotExtended < ServerError; end
|
38
|
+
|
39
|
+
# 511 Network Authentication Required
|
40
|
+
class NetworkAuthenticationRequired < ServerError; end
|
41
|
+
end
|
42
|
+
end
|
data/my_api/Gemfile.lock
CHANGED
@@ -45,7 +45,7 @@ GEM
|
|
45
45
|
rainbow
|
46
46
|
thor
|
47
47
|
zeitwerk
|
48
|
-
aws-partitions (1.
|
48
|
+
aws-partitions (1.290.0)
|
49
49
|
aws-sdk-apigateway (1.37.0)
|
50
50
|
aws-sdk-core (~> 3, >= 3.71.0)
|
51
51
|
aws-sigv4 (~> 1.1)
|
@@ -55,7 +55,7 @@ GEM
|
|
55
55
|
aws-sdk-cloudwatchlogs (1.29.0)
|
56
56
|
aws-sdk-core (~> 3, >= 3.71.0)
|
57
57
|
aws-sigv4 (~> 1.1)
|
58
|
-
aws-sdk-core (3.
|
58
|
+
aws-sdk-core (3.92.0)
|
59
59
|
aws-eventstream (~> 1.0, >= 1.0.2)
|
60
60
|
aws-partitions (~> 1, >= 1.239.0)
|
61
61
|
aws-sigv4 (~> 1.1)
|
@@ -118,7 +118,7 @@ GEM
|
|
118
118
|
hashie (4.1.0)
|
119
119
|
i18n (1.8.2)
|
120
120
|
concurrent-ruby (~> 1.0)
|
121
|
-
jets (2.3.
|
121
|
+
jets (2.3.15)
|
122
122
|
actionmailer (~> 6.0.0)
|
123
123
|
actionpack (~> 6.0.0)
|
124
124
|
actionview (~> 6.0.0)
|
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.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ryz310
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -267,10 +267,15 @@ files:
|
|
267
267
|
- lib/my_api_client.rb
|
268
268
|
- lib/my_api_client/base.rb
|
269
269
|
- lib/my_api_client/config.rb
|
270
|
+
- lib/my_api_client/default_error_handlers.rb
|
270
271
|
- lib/my_api_client/error_handling.rb
|
271
272
|
- lib/my_api_client/error_handling/generator.rb
|
272
273
|
- lib/my_api_client/error_handling/retry_option_processor.rb
|
273
274
|
- lib/my_api_client/errors.rb
|
275
|
+
- lib/my_api_client/errors/api_limit_error.rb
|
276
|
+
- lib/my_api_client/errors/client_error.rb
|
277
|
+
- lib/my_api_client/errors/network_error.rb
|
278
|
+
- lib/my_api_client/errors/server_error.rb
|
274
279
|
- lib/my_api_client/exceptions.rb
|
275
280
|
- lib/my_api_client/integrations/bugsnag.rb
|
276
281
|
- lib/my_api_client/params/params.rb
|