my_api_client 0.14.0 → 0.18.0
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 +99 -53
- data/.dependabot/config.yml +19 -1
- data/.rubocop.yml +5 -1
- data/.rubocop_challenge.yml +5 -0
- data/.rubocop_todo.yml +53 -1
- data/CHANGELOG.md +192 -0
- data/Gemfile +0 -3
- data/Gemfile.lock +60 -56
- data/README.jp.md +159 -24
- data/bin/console +4 -0
- data/example/api_clients/application_api_client.rb +2 -10
- data/example/api_clients/my_pagination_api_client.rb +18 -0
- data/example/api_clients/my_rest_api_client.rb +9 -3
- data/lib/generators/rails/USAGE +1 -1
- data/lib/generators/rails/api_client_generator.rb +6 -0
- data/lib/generators/rails/templates/api_client.rb.erb +1 -1
- data/lib/generators/rails/templates/application_api_client.rb.erb +0 -11
- data/lib/generators/rspec/USAGE +1 -1
- data/lib/generators/rspec/api_client_generator.rb +6 -0
- data/lib/generators/rspec/templates/api_client_spec.rb.erb +23 -16
- data/lib/my_api_client.rb +7 -0
- data/lib/my_api_client/base.rb +4 -2
- data/lib/my_api_client/default_error_handlers.rb +64 -0
- data/lib/my_api_client/error_handling.rb +6 -6
- data/lib/my_api_client/error_handling/generator.rb +23 -7
- data/lib/my_api_client/errors.rb +1 -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/params/params.rb +1 -3
- data/lib/my_api_client/request.rb +29 -34
- data/lib/my_api_client/request/basic.rb +32 -0
- data/lib/my_api_client/request/executor.rb +1 -1
- data/lib/my_api_client/request/pagination.rb +39 -0
- data/lib/my_api_client/version.rb +1 -1
- data/my_api/.ruby-version +1 -1
- data/my_api/Gemfile.lock +86 -86
- data/my_api/README.md +6 -0
- data/my_api/app/controllers/pagination_controller.rb +58 -0
- data/my_api/config/routes.rb +1 -0
- data/my_api/spec/controllers/pagination_controller_spec.rb +73 -0
- data/my_api/spec/controllers/rest_controller_spec.rb +23 -5
- data/my_api/spec/spec_helper.rb +5 -0
- data/my_api_client.gemspec +2 -2
- data/rails_app/rails_5.2/.rspec +3 -0
- data/rails_app/rails_5.2/Gemfile +17 -0
- data/rails_app/rails_5.2/Gemfile.lock +171 -0
- data/rails_app/rails_5.2/README.md +24 -0
- data/rails_app/rails_5.2/Rakefile +8 -0
- data/rails_app/rails_5.2/app/controllers/application_controller.rb +4 -0
- data/rails_app/rails_5.2/app/jobs/application_job.rb +4 -0
- data/rails_app/rails_5.2/bin/bundle +5 -0
- data/rails_app/rails_5.2/bin/rails +6 -0
- data/rails_app/rails_5.2/bin/rake +6 -0
- data/rails_app/rails_5.2/bin/setup +27 -0
- data/rails_app/rails_5.2/bin/update +27 -0
- data/rails_app/rails_5.2/config.ru +7 -0
- data/rails_app/rails_5.2/config/application.rb +37 -0
- data/rails_app/rails_5.2/config/boot.rb +6 -0
- data/rails_app/rails_5.2/config/credentials.yml.enc +1 -0
- data/rails_app/rails_5.2/config/environment.rb +7 -0
- data/rails_app/rails_5.2/config/environments/development.rb +41 -0
- data/rails_app/rails_5.2/config/environments/production.rb +70 -0
- data/rails_app/rails_5.2/config/environments/test.rb +38 -0
- data/rails_app/rails_5.2/config/initializers/application_controller_renderer.rb +9 -0
- data/rails_app/rails_5.2/config/initializers/backtrace_silencers.rb +8 -0
- data/rails_app/rails_5.2/config/initializers/cors.rb +17 -0
- data/rails_app/rails_5.2/config/initializers/filter_parameter_logging.rb +6 -0
- data/rails_app/rails_5.2/config/initializers/inflections.rb +17 -0
- data/rails_app/rails_5.2/config/initializers/mime_types.rb +5 -0
- data/rails_app/rails_5.2/config/initializers/wrap_parameters.rb +11 -0
- data/rails_app/rails_5.2/config/locales/en.yml +33 -0
- data/rails_app/rails_5.2/config/routes.rb +5 -0
- data/rails_app/rails_5.2/config/spring.rb +8 -0
- data/rails_app/rails_5.2/public/robots.txt +1 -0
- data/rails_app/rails_5.2/spec/rails_helper.rb +14 -0
- data/rails_app/rails_5.2/spec/spec_helper.rb +13 -0
- data/rails_app/rails_6.0/.rspec +3 -0
- data/rails_app/rails_6.0/Gemfile +17 -0
- data/rails_app/rails_6.0/Gemfile.lock +186 -0
- data/rails_app/rails_6.0/README.md +24 -0
- data/rails_app/rails_6.0/Rakefile +8 -0
- data/rails_app/rails_6.0/app/controllers/application_controller.rb +4 -0
- data/rails_app/rails_6.0/app/jobs/application_job.rb +9 -0
- data/rails_app/rails_6.0/bin/rails +6 -0
- data/rails_app/rails_6.0/bin/rake +6 -0
- data/rails_app/rails_6.0/bin/setup +27 -0
- data/rails_app/rails_6.0/config.ru +7 -0
- data/rails_app/rails_6.0/config/application.rb +39 -0
- data/rails_app/rails_6.0/config/boot.rb +6 -0
- data/rails_app/rails_6.0/config/credentials.yml.enc +1 -0
- data/rails_app/rails_6.0/config/environment.rb +7 -0
- data/rails_app/rails_6.0/config/environments/development.rb +39 -0
- data/rails_app/rails_6.0/config/environments/production.rb +90 -0
- data/rails_app/rails_6.0/config/environments/test.rb +41 -0
- data/rails_app/rails_6.0/config/initializers/application_controller_renderer.rb +9 -0
- data/rails_app/rails_6.0/config/initializers/backtrace_silencers.rb +8 -0
- data/rails_app/rails_6.0/config/initializers/cors.rb +17 -0
- data/rails_app/rails_6.0/config/initializers/filter_parameter_logging.rb +6 -0
- data/rails_app/rails_6.0/config/initializers/inflections.rb +17 -0
- data/rails_app/rails_6.0/config/initializers/mime_types.rb +5 -0
- data/rails_app/rails_6.0/config/initializers/wrap_parameters.rb +11 -0
- data/rails_app/rails_6.0/config/locales/en.yml +33 -0
- data/rails_app/rails_6.0/config/routes.rb +5 -0
- data/rails_app/rails_6.0/config/spring.rb +8 -0
- data/rails_app/rails_6.0/public/robots.txt +1 -0
- data/rails_app/rails_6.0/spec/rails_helper.rb +14 -0
- data/rails_app/rails_6.0/spec/spec_helper.rb +13 -0
- metadata +81 -8
- data/gemfiles/rails_4.2.gemfile +0 -15
- data/renovate.json +0 -21
data/Gemfile
CHANGED
@@ -4,9 +4,6 @@ source 'https://rubygems.org'
|
|
4
4
|
|
5
5
|
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
6
6
|
|
7
|
-
# Workaound for ruby 2.4. Because activesupport v6.0.0 requires ruby 2.5 over.
|
8
|
-
gem 'activesupport', '< 6.0.0'
|
9
|
-
|
10
7
|
group :integrations, optional: true do
|
11
8
|
gem 'bugsnag', '>= 6.11.0'
|
12
9
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
my_api_client (0.
|
5
|
-
activesupport (>=
|
4
|
+
my_api_client (0.18.0)
|
5
|
+
activesupport (>= 5.0.0)
|
6
6
|
faraday (>= 0.17.1)
|
7
7
|
jsonpath
|
8
8
|
sawyer (>= 0.8.2)
|
@@ -10,79 +10,84 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
activesupport (
|
13
|
+
activesupport (6.0.3.4)
|
14
14
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
15
|
i18n (>= 0.7, < 2)
|
16
16
|
minitest (~> 5.1)
|
17
17
|
tzinfo (~> 1.1)
|
18
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
18
19
|
addressable (2.7.0)
|
19
20
|
public_suffix (>= 2.0.2, < 5.0)
|
20
|
-
ast (2.4.
|
21
|
-
bugsnag (6.
|
21
|
+
ast (2.4.1)
|
22
|
+
bugsnag (6.18.0)
|
22
23
|
concurrent-ruby (~> 1.0)
|
23
|
-
byebug (11.1.
|
24
|
-
coderay (1.1.
|
25
|
-
concurrent-ruby (1.1.
|
26
|
-
crack (0.4.
|
27
|
-
|
28
|
-
diff-lcs (1.3)
|
24
|
+
byebug (11.1.3)
|
25
|
+
coderay (1.1.3)
|
26
|
+
concurrent-ruby (1.1.7)
|
27
|
+
crack (0.4.4)
|
28
|
+
diff-lcs (1.4.4)
|
29
29
|
docile (1.3.2)
|
30
|
-
faraday (1.
|
30
|
+
faraday (1.1.0)
|
31
31
|
multipart-post (>= 1.2, < 3)
|
32
|
+
ruby2_keywords
|
32
33
|
hashdiff (1.0.1)
|
33
|
-
i18n (1.8.
|
34
|
+
i18n (1.8.5)
|
34
35
|
concurrent-ruby (~> 1.0)
|
35
|
-
|
36
|
-
|
37
|
-
jsonpath (1.0.5)
|
36
|
+
json (2.3.1)
|
37
|
+
jsonpath (1.0.6)
|
38
38
|
multi_json
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
multi_json (1.14.1)
|
39
|
+
method_source (1.0.0)
|
40
|
+
minitest (5.14.2)
|
41
|
+
multi_json (1.15.0)
|
43
42
|
multipart-post (2.1.1)
|
44
|
-
parallel (1.
|
45
|
-
parser (2.7.0
|
46
|
-
ast (~> 2.4.
|
47
|
-
pry (0.
|
48
|
-
coderay (~> 1.1
|
49
|
-
method_source (~>
|
50
|
-
pry-byebug (3.
|
43
|
+
parallel (1.20.1)
|
44
|
+
parser (2.7.2.0)
|
45
|
+
ast (~> 2.4.1)
|
46
|
+
pry (0.13.1)
|
47
|
+
coderay (~> 1.1)
|
48
|
+
method_source (~> 1.0)
|
49
|
+
pry-byebug (3.9.0)
|
51
50
|
byebug (~> 11.0)
|
52
|
-
pry (~> 0.
|
53
|
-
public_suffix (4.0.
|
51
|
+
pry (~> 0.13.0)
|
52
|
+
public_suffix (4.0.6)
|
54
53
|
rainbow (3.0.0)
|
55
54
|
rake (13.0.1)
|
55
|
+
regexp_parser (2.0.0)
|
56
56
|
rexml (3.2.4)
|
57
|
-
rspec (3.
|
58
|
-
rspec-core (~> 3.
|
59
|
-
rspec-expectations (~> 3.
|
60
|
-
rspec-mocks (~> 3.
|
61
|
-
rspec-core (3.
|
62
|
-
rspec-support (~> 3.
|
63
|
-
rspec-expectations (3.
|
57
|
+
rspec (3.10.0)
|
58
|
+
rspec-core (~> 3.10.0)
|
59
|
+
rspec-expectations (~> 3.10.0)
|
60
|
+
rspec-mocks (~> 3.10.0)
|
61
|
+
rspec-core (3.10.0)
|
62
|
+
rspec-support (~> 3.10.0)
|
63
|
+
rspec-expectations (3.10.0)
|
64
64
|
diff-lcs (>= 1.2.0, < 2.0)
|
65
|
-
rspec-support (~> 3.
|
66
|
-
rspec-mocks (3.
|
65
|
+
rspec-support (~> 3.10.0)
|
66
|
+
rspec-mocks (3.10.0)
|
67
67
|
diff-lcs (>= 1.2.0, < 2.0)
|
68
|
-
rspec-support (~> 3.
|
69
|
-
rspec-support (3.
|
68
|
+
rspec-support (~> 3.10.0)
|
69
|
+
rspec-support (3.10.0)
|
70
70
|
rspec_junit_formatter (0.4.1)
|
71
71
|
rspec-core (>= 2, < 4, != 2.12.0)
|
72
|
-
rubocop (
|
73
|
-
jaro_winkler (~> 1.5.1)
|
72
|
+
rubocop (1.5.1)
|
74
73
|
parallel (~> 1.10)
|
75
|
-
parser (>= 2.7.
|
74
|
+
parser (>= 2.7.1.5)
|
76
75
|
rainbow (>= 2.2.2, < 4.0)
|
76
|
+
regexp_parser (>= 2.0)
|
77
77
|
rexml
|
78
|
+
rubocop-ast (>= 1.2.0)
|
78
79
|
ruby-progressbar (~> 1.7)
|
79
|
-
unicode-display_width (>= 1.4.0, <
|
80
|
-
rubocop-
|
81
|
-
|
82
|
-
rubocop-
|
83
|
-
rubocop (>= 0.
|
80
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
81
|
+
rubocop-ast (1.3.0)
|
82
|
+
parser (>= 2.7.1.5)
|
83
|
+
rubocop-performance (1.9.1)
|
84
|
+
rubocop (>= 0.90.0, < 2.0)
|
85
|
+
rubocop-ast (>= 0.4.0)
|
86
|
+
rubocop-rspec (2.0.1)
|
87
|
+
rubocop (~> 1.0)
|
88
|
+
rubocop-ast (>= 1.1.0)
|
84
89
|
ruby-progressbar (1.10.1)
|
85
|
-
|
90
|
+
ruby2_keywords (0.0.2)
|
86
91
|
sawyer (0.8.2)
|
87
92
|
addressable (>= 2.3.5)
|
88
93
|
faraday (> 0.8, < 2.0)
|
@@ -92,21 +97,20 @@ GEM
|
|
92
97
|
simplecov-html (~> 0.10.0)
|
93
98
|
simplecov-html (0.10.2)
|
94
99
|
thread_safe (0.3.6)
|
95
|
-
|
96
|
-
tzinfo (1.2.6)
|
100
|
+
tzinfo (1.2.8)
|
97
101
|
thread_safe (~> 0.1)
|
98
|
-
unicode-display_width (1.
|
99
|
-
webmock (3.
|
102
|
+
unicode-display_width (1.7.0)
|
103
|
+
webmock (3.10.0)
|
100
104
|
addressable (>= 2.3.6)
|
101
105
|
crack (>= 0.3.2)
|
102
106
|
hashdiff (>= 0.4.0, < 2.0.0)
|
103
|
-
yard (0.9.
|
107
|
+
yard (0.9.25)
|
108
|
+
zeitwerk (2.4.2)
|
104
109
|
|
105
110
|
PLATFORMS
|
106
111
|
ruby
|
107
112
|
|
108
113
|
DEPENDENCIES
|
109
|
-
activesupport (< 6.0.0)
|
110
114
|
bugsnag (>= 6.11.0)
|
111
115
|
bundler (>= 2.0)
|
112
116
|
my_api_client!
|
@@ -122,4 +126,4 @@ DEPENDENCIES
|
|
122
126
|
yard
|
123
127
|
|
124
128
|
BUNDLED WITH
|
125
|
-
2.1.
|
129
|
+
2.1.4
|
data/README.jp.md
CHANGED
@@ -6,12 +6,14 @@ 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
|
|
13
|
-
* Ruby 2.
|
14
|
-
* Rails
|
15
|
+
* Ruby 2.5, 2.6, 2.7
|
16
|
+
* Rails 5.0, 5.1, 5.2, 6.0
|
15
17
|
|
16
18
|
## Installation
|
17
19
|
|
@@ -24,7 +26,7 @@ gem 'my_api_client'
|
|
24
26
|
Ruby on Rails を利用している場合は `generator` 機能を利用できます。
|
25
27
|
|
26
28
|
```sh
|
27
|
-
$ rails g api_client path/to/resource get:path/to/resource
|
29
|
+
$ rails g api_client path/to/resource get:path/to/resource --endpoint https://example.com
|
28
30
|
|
29
31
|
create app/api_clients/application_api_client.rb
|
30
32
|
create app/api_clients/path/to/resource_api_client.rb
|
@@ -83,32 +85,95 @@ api_clinet.get_users #=> #<Sawyer::Response>
|
|
83
85
|
|
84
86
|
続いて、 `#get_users` や `#post_user` を定義します。メソッド名には API のタイトルを付けると良いと思います。メソッド内部で `#get` や `#post` を呼び出していますが、これがリクエスト時の HTTP Method になります。他にも `#patch` `#put` `#delete` が利用可能です。
|
85
87
|
|
88
|
+
### Pagination
|
89
|
+
|
90
|
+
API の中にはレスポンスに結果の続きを取得するための URL を含んでいるものがあります。
|
91
|
+
|
92
|
+
MyApiClient では、このような API を enumerable に扱うための `#pageable_get` というメソッドを用意しています。以下に例を示します。
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
class MyPaginationApiClient < ApplicationApiClient
|
96
|
+
endpoint 'https://example.com/v1'
|
97
|
+
|
98
|
+
# GET pagination?page=1
|
99
|
+
def pagination
|
100
|
+
pageable_get 'pagination', paging: '$.links.next', headers: headers, query: { page: 1 }
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def headers
|
106
|
+
{ 'Content-Type': 'application/json;charset=UTF-8' }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
上記の例の場合、最初に `GET https://example.com/v1/pagination?page=1` に対してリクエストが実行され、続けてレスポンス JSON の `$.link.next` に含まれる URL に対して enumerable にリクエストを実行します。
|
112
|
+
|
113
|
+
例えば以下のようなレスポンスであれば、`$.link.next` は `"https://example.com/pagination?page=3"` を示します。
|
114
|
+
|
115
|
+
```json
|
116
|
+
{
|
117
|
+
"links": {
|
118
|
+
"next": "https://example.com/pagination?page=3",
|
119
|
+
"previous": "https://example.com/pagination?page=1",
|
120
|
+
},
|
121
|
+
"page": 2
|
122
|
+
}
|
123
|
+
```
|
124
|
+
|
125
|
+
そして `#pageable_get` は [Enumerator::Lazy](https://docs.ruby-lang.org/ja/latest/class/Enumerator=3a=3aLazy.html) を返すので、 `#each` や `#next` を実行することで次の結果を取得できます。
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
api_clinet = MyPaginationApiClient.new
|
129
|
+
api_clinet.pagination.each do |response|
|
130
|
+
# Do something.
|
131
|
+
end
|
132
|
+
|
133
|
+
p = api_clinet.pagination
|
134
|
+
p.next # => 1st page result
|
135
|
+
p.next # => 2nd page result
|
136
|
+
p.next # => 3rd page result
|
137
|
+
```
|
138
|
+
|
139
|
+
なお、`#each` はレスポンスに含まれる `paging` の値が nil になるまで繰り返されるのでご注意ください。例えば `#take` と組み合わせることでページネーションの上限を設定できます。
|
140
|
+
|
141
|
+
`#pageable_get` の alias として `#pget` も利用可能です。
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
# GET pagination?page=1
|
145
|
+
def pagination
|
146
|
+
pget 'pagination', paging: '$.links.next', headers: headers, query: { page: 1 }
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
86
150
|
### Error handling
|
87
151
|
|
88
|
-
|
152
|
+
`my_api_client` ではレスポンスの内容によって例外を発生させるエラーハンドリングを定義できます。ここでは例として前述のコードにエラーハンドリングを定義しています。
|
89
153
|
|
90
154
|
```ruby
|
91
155
|
class ExampleApiClient < MyApiClient::Base
|
92
156
|
endpoint 'https://example.com'
|
93
157
|
|
94
|
-
error_handling status_code: 400..499,
|
158
|
+
error_handling status_code: 400..499,
|
159
|
+
raise: MyApiClient::ClientError
|
95
160
|
|
96
|
-
error_handling status_code: 500..599 do |
|
161
|
+
error_handling status_code: 500..599, raise: MyApiClient::ServerError do |_params, logger|
|
97
162
|
logger.warn 'Server error occurred.'
|
98
|
-
raise MyApiClient::ServerError, params
|
99
163
|
end
|
100
164
|
|
101
|
-
error_handling json: { '$.errors.code': 10..19 },
|
165
|
+
error_handling json: { '$.errors.code': 10..19 },
|
166
|
+
raise: MyApiClient::ClientError,
|
167
|
+
with: :my_error_handling
|
102
168
|
|
103
169
|
# Omission...
|
104
170
|
|
105
171
|
private
|
106
172
|
|
107
|
-
# @param params [MyApiClient::Params::Params] HTTP
|
173
|
+
# @param params [MyApiClient::Params::Params] HTTP reqest and response params
|
108
174
|
# @param logger [MyApiClient::Request::Logger] Logger for a request processing
|
109
175
|
def my_error_handling(params, logger)
|
110
176
|
logger.warn "Response Body: #{params.response.body.inspect}"
|
111
|
-
raise MyApiClient::ClientError, params
|
112
177
|
end
|
113
178
|
end
|
114
179
|
```
|
@@ -121,29 +186,26 @@ error_handling status_code: 400..499, raise: MyApiClient::ClientError
|
|
121
186
|
|
122
187
|
これは `ExampleApiClient` からのリクエスト全てにおいて、レスポンスのステータスコードが `400..499` であった場合に `MyApiClient::ClientError` が例外として発生するようになります。 `ExampleApiClient` を継承したクラスにもエラーハンドリングは適用されます。ステータスコードのエラーハンドリングは親クラスで定義すると良いと思います。
|
123
188
|
|
124
|
-
なお、 `status_code` には `Integer` `Range` `Regexp`
|
189
|
+
なお、 `status_code` には `Integer` `Range` `Regexp` が指定可能です。
|
190
|
+
|
191
|
+
`raise` には `MyApiClient::Error` を継承したクラスが指定可能です。`my_api_client` で標準で定義しているエラークラスについては以下のソースコードをご確認下さい。 `raise` を省略した場合は `MyApiClient::Error` を発生するようになります。
|
125
192
|
|
126
|
-
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
|
127
194
|
|
128
|
-
次に、 `
|
195
|
+
次に、 `block` を指定する場合について。
|
129
196
|
|
130
197
|
```ruby
|
131
|
-
error_handling status_code: 500..599 do |
|
198
|
+
error_handling status_code: 500..599, raise: MyApiClient::ServerError do |_params, logger|
|
132
199
|
logger.warn 'Server error occurred.'
|
133
|
-
raise MyApiClient::ServerError, params
|
134
200
|
end
|
135
201
|
```
|
136
202
|
|
137
|
-
上記の例であれば、ステータスコードが `500..599` の場合に `block` の内容が実行れます。引数の `params` にはリクエスト情報とレスポンス情報が含まれています。`logger` はログ出力用インスタンスですが、このインスタンスを使ってログ出力すると、以下のようにリクエスト情報がログ出力に含まれるようになり、デバッグの際に便利です。
|
203
|
+
上記の例であれば、ステータスコードが `500..599` の場合に `MyApiClient::ServerError` を発生させる前に `block` の内容が実行れます。引数の `params` にはリクエスト情報とレスポンス情報が含まれています。`logger` はログ出力用インスタンスですが、このインスタンスを使ってログ出力すると、以下のようにリクエスト情報がログ出力に含まれるようになり、デバッグの際に便利です。
|
138
204
|
|
139
205
|
```text
|
140
206
|
API request `GET https://example.com/path/to/resouce`: "Server error occurred."
|
141
207
|
```
|
142
208
|
|
143
|
-
リクエストに失敗した場合は例外処理を実行する、という設計が一般的だと思われるので、基本的にブロックの最後に `raise` を実行する事になると思います。
|
144
|
-
|
145
|
-
最後に `json` と `with` を利用する場合について。
|
146
|
-
|
147
209
|
```ruby
|
148
210
|
error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
149
211
|
```
|
@@ -159,17 +221,28 @@ error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
|
159
221
|
}
|
160
222
|
```
|
161
223
|
|
162
|
-
`with`
|
224
|
+
`with` にはインスタンスメソッド名を指定することで、エラーを検出した際、例外を発生させる前に任意のメソッドを実行させることができます。メソッドに渡される引数は `block` 定義の場合と同じく `params` と `logger` です。なお、 `block` と `with` は同時には利用できません。
|
163
225
|
|
164
226
|
```ruby
|
165
227
|
# @param params [MyApiClient::Params::Params] HTTP req and res params
|
166
228
|
# @param logger [MyApiClient::Request::Logger] Logger for a request processing
|
167
229
|
def my_error_handling(params, logger)
|
168
230
|
logger.warn "Response Body: #{params.response.body.inspect}"
|
169
|
-
raise MyApiClient::ClientError, params
|
170
231
|
end
|
171
232
|
```
|
172
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
|
+
|
173
246
|
#### Symbol を利用する
|
174
247
|
|
175
248
|
```ruby
|
@@ -238,7 +311,9 @@ end
|
|
238
311
|
|
239
312
|
API リクエストを何度も実行していると回線の不調などによりネットワークエラーが発生する事があります。長時間ネットワークが使えなくなるケースもありますが、瞬間的なエラーであるケースも多々あります。 `MyApiClient` ではネットワーク系の例外はまとめて `MyApiClient::NetworkError` として `raise` されます。この例外の詳細は後述しますが、 `retry_on` を利用する事で、 `ActiveJob` のように任意の例外処理を補足して、一定回数、一定の期間を空けて API リクエストをリトライさせる事ができます。
|
240
313
|
|
241
|
-
|
314
|
+
なお、 `retry_on MyApiClient::NetworkError` は標準実装されているため、特別に定義せずとも自動的に適用されます。 `wait` や `attempts` に任意の値を設定したい場合のみ定義してご利用ください。
|
315
|
+
|
316
|
+
ただし、 `ActiveJob` とは異なり同期処理でリトライするため、ネットワークの瞬断に備えたリトライ以外ではあまり使う機会はないのではないかと思います。上記の例のように API Rate Limit に備えてリトライするケースもあるかと思いますが、こちらは `ActiveJob` で対応した方が良いかもしれません。
|
242
317
|
|
243
318
|
ちなみに一応 `discard_on` も実装していますが、作者自身が有効な用途を見出せていないので、詳細は割愛します。良い利用方法があれば教えてください。
|
244
319
|
|
@@ -567,6 +642,66 @@ rescue MyApiClient::Error => e
|
|
567
642
|
end
|
568
643
|
```
|
569
644
|
|
645
|
+
## Deployment
|
646
|
+
|
647
|
+
この gem のリリースには [gem_comet](https://github.com/ryz310/gem_comet) を利用しています。
|
648
|
+
`gem_comet` の README.md にも使い方が載っていますが、備忘録のため、こちらにもリリースフローを記載しておきます。
|
649
|
+
|
650
|
+
### Preparement
|
651
|
+
|
652
|
+
以下のコマンドで `.envrc` を作成し、 `GITHUB_ACCESS_TOKEN` を設定します。
|
653
|
+
|
654
|
+
```sh
|
655
|
+
$ cp .envrc.skeleton .envrc
|
656
|
+
```
|
657
|
+
|
658
|
+
以下のコマンドで `gem_comet` をインストールします。
|
659
|
+
|
660
|
+
```sh
|
661
|
+
$ gem install gem_comet
|
662
|
+
```
|
663
|
+
|
664
|
+
### USAGE
|
665
|
+
|
666
|
+
以下のコマンドで、最後のリリースから現在までに merge した PR の一覧を確認できます。
|
667
|
+
|
668
|
+
```sh
|
669
|
+
$ gem_comet changelog
|
670
|
+
```
|
671
|
+
|
672
|
+
以下のコマンドで gem のリリースを実行します。
|
673
|
+
`{VERSION}` には新しく付与するバージョン番号を指定します。
|
674
|
+
|
675
|
+
```sh
|
676
|
+
$ gem_comet release {VERSION}
|
677
|
+
```
|
678
|
+
|
679
|
+
実行すると、 https://github.com/ryz310/my_api_client/pulls に以下のような PR が作成されます。
|
680
|
+
|
681
|
+
* [Update v0\.16\.1](https://github.com/ryz310/my_api_client/pull/297)
|
682
|
+
* [Release v0\.16\.1](https://github.com/ryz310/my_api_client/pull/298)
|
683
|
+
|
684
|
+
まず、 `Update v{VERSION}` という PR から merge に取り掛かります。
|
685
|
+
|
686
|
+
PR のコメントにも TODO が記載されていますが、まず、バージョン番号が正しく採番されているかを確認します。
|
687
|
+
|
688
|
+
See: [314a4c0](https://github.com/ryz310/my_api_client/pull/297/commits/314a4c06f66324ce77b640b1ee8db5c84ee038a2)
|
689
|
+
|
690
|
+
次に `CHANGELOG.md` を編集して、 CHANGELOG を見やすく整理します。
|
691
|
+
|
692
|
+
See: [33a2d17](https://github.com/ryz310/my_api_client/pull/297/commits/33a2d1703c773813c837e74ee3181906b2f2e502)
|
693
|
+
|
694
|
+
これらが整ったら、 `Update v{VERSION}` を merge します。
|
695
|
+
|
696
|
+
これでリリース準備が整ったので、`Release v{VERSION}` の merge に取り掛かります。
|
697
|
+
|
698
|
+
この PR にこれからリリースする gem に対する変更が全て載っています。
|
699
|
+
変更内容の最終確認をして、 CI も通ったことを確認したら `Release v{VERSION}` を merge します。
|
700
|
+
|
701
|
+
あとは Circle CI 側で gem のリリースが自動実行されるので、暫く待ちましょう。
|
702
|
+
|
703
|
+
お疲れさまでした :tea:
|
704
|
+
|
570
705
|
## Contributing
|
571
706
|
|
572
707
|
不具合の報告や Pull Request を歓迎しています。OSS という事で自分はなるべく頑張って英語を使うようにしていますが、日本語での報告でも大丈夫です :+1:
|