my_api_client 0.14.0 → 0.18.0

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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +99 -53
  3. data/.dependabot/config.yml +19 -1
  4. data/.rubocop.yml +5 -1
  5. data/.rubocop_challenge.yml +5 -0
  6. data/.rubocop_todo.yml +53 -1
  7. data/CHANGELOG.md +192 -0
  8. data/Gemfile +0 -3
  9. data/Gemfile.lock +60 -56
  10. data/README.jp.md +159 -24
  11. data/bin/console +4 -0
  12. data/example/api_clients/application_api_client.rb +2 -10
  13. data/example/api_clients/my_pagination_api_client.rb +18 -0
  14. data/example/api_clients/my_rest_api_client.rb +9 -3
  15. data/lib/generators/rails/USAGE +1 -1
  16. data/lib/generators/rails/api_client_generator.rb +6 -0
  17. data/lib/generators/rails/templates/api_client.rb.erb +1 -1
  18. data/lib/generators/rails/templates/application_api_client.rb.erb +0 -11
  19. data/lib/generators/rspec/USAGE +1 -1
  20. data/lib/generators/rspec/api_client_generator.rb +6 -0
  21. data/lib/generators/rspec/templates/api_client_spec.rb.erb +23 -16
  22. data/lib/my_api_client.rb +7 -0
  23. data/lib/my_api_client/base.rb +4 -2
  24. data/lib/my_api_client/default_error_handlers.rb +64 -0
  25. data/lib/my_api_client/error_handling.rb +6 -6
  26. data/lib/my_api_client/error_handling/generator.rb +23 -7
  27. data/lib/my_api_client/errors.rb +1 -53
  28. data/lib/my_api_client/errors/api_limit_error.rb +6 -0
  29. data/lib/my_api_client/errors/client_error.rb +93 -0
  30. data/lib/my_api_client/errors/network_error.rb +43 -0
  31. data/lib/my_api_client/errors/server_error.rb +42 -0
  32. data/lib/my_api_client/params/params.rb +1 -3
  33. data/lib/my_api_client/request.rb +29 -34
  34. data/lib/my_api_client/request/basic.rb +32 -0
  35. data/lib/my_api_client/request/executor.rb +1 -1
  36. data/lib/my_api_client/request/pagination.rb +39 -0
  37. data/lib/my_api_client/version.rb +1 -1
  38. data/my_api/.ruby-version +1 -1
  39. data/my_api/Gemfile.lock +86 -86
  40. data/my_api/README.md +6 -0
  41. data/my_api/app/controllers/pagination_controller.rb +58 -0
  42. data/my_api/config/routes.rb +1 -0
  43. data/my_api/spec/controllers/pagination_controller_spec.rb +73 -0
  44. data/my_api/spec/controllers/rest_controller_spec.rb +23 -5
  45. data/my_api/spec/spec_helper.rb +5 -0
  46. data/my_api_client.gemspec +2 -2
  47. data/rails_app/rails_5.2/.rspec +3 -0
  48. data/rails_app/rails_5.2/Gemfile +17 -0
  49. data/rails_app/rails_5.2/Gemfile.lock +171 -0
  50. data/rails_app/rails_5.2/README.md +24 -0
  51. data/rails_app/rails_5.2/Rakefile +8 -0
  52. data/rails_app/rails_5.2/app/controllers/application_controller.rb +4 -0
  53. data/rails_app/rails_5.2/app/jobs/application_job.rb +4 -0
  54. data/rails_app/rails_5.2/bin/bundle +5 -0
  55. data/rails_app/rails_5.2/bin/rails +6 -0
  56. data/rails_app/rails_5.2/bin/rake +6 -0
  57. data/rails_app/rails_5.2/bin/setup +27 -0
  58. data/rails_app/rails_5.2/bin/update +27 -0
  59. data/rails_app/rails_5.2/config.ru +7 -0
  60. data/rails_app/rails_5.2/config/application.rb +37 -0
  61. data/rails_app/rails_5.2/config/boot.rb +6 -0
  62. data/rails_app/rails_5.2/config/credentials.yml.enc +1 -0
  63. data/rails_app/rails_5.2/config/environment.rb +7 -0
  64. data/rails_app/rails_5.2/config/environments/development.rb +41 -0
  65. data/rails_app/rails_5.2/config/environments/production.rb +70 -0
  66. data/rails_app/rails_5.2/config/environments/test.rb +38 -0
  67. data/rails_app/rails_5.2/config/initializers/application_controller_renderer.rb +9 -0
  68. data/rails_app/rails_5.2/config/initializers/backtrace_silencers.rb +8 -0
  69. data/rails_app/rails_5.2/config/initializers/cors.rb +17 -0
  70. data/rails_app/rails_5.2/config/initializers/filter_parameter_logging.rb +6 -0
  71. data/rails_app/rails_5.2/config/initializers/inflections.rb +17 -0
  72. data/rails_app/rails_5.2/config/initializers/mime_types.rb +5 -0
  73. data/rails_app/rails_5.2/config/initializers/wrap_parameters.rb +11 -0
  74. data/rails_app/rails_5.2/config/locales/en.yml +33 -0
  75. data/rails_app/rails_5.2/config/routes.rb +5 -0
  76. data/rails_app/rails_5.2/config/spring.rb +8 -0
  77. data/rails_app/rails_5.2/public/robots.txt +1 -0
  78. data/rails_app/rails_5.2/spec/rails_helper.rb +14 -0
  79. data/rails_app/rails_5.2/spec/spec_helper.rb +13 -0
  80. data/rails_app/rails_6.0/.rspec +3 -0
  81. data/rails_app/rails_6.0/Gemfile +17 -0
  82. data/rails_app/rails_6.0/Gemfile.lock +186 -0
  83. data/rails_app/rails_6.0/README.md +24 -0
  84. data/rails_app/rails_6.0/Rakefile +8 -0
  85. data/rails_app/rails_6.0/app/controllers/application_controller.rb +4 -0
  86. data/rails_app/rails_6.0/app/jobs/application_job.rb +9 -0
  87. data/rails_app/rails_6.0/bin/rails +6 -0
  88. data/rails_app/rails_6.0/bin/rake +6 -0
  89. data/rails_app/rails_6.0/bin/setup +27 -0
  90. data/rails_app/rails_6.0/config.ru +7 -0
  91. data/rails_app/rails_6.0/config/application.rb +39 -0
  92. data/rails_app/rails_6.0/config/boot.rb +6 -0
  93. data/rails_app/rails_6.0/config/credentials.yml.enc +1 -0
  94. data/rails_app/rails_6.0/config/environment.rb +7 -0
  95. data/rails_app/rails_6.0/config/environments/development.rb +39 -0
  96. data/rails_app/rails_6.0/config/environments/production.rb +90 -0
  97. data/rails_app/rails_6.0/config/environments/test.rb +41 -0
  98. data/rails_app/rails_6.0/config/initializers/application_controller_renderer.rb +9 -0
  99. data/rails_app/rails_6.0/config/initializers/backtrace_silencers.rb +8 -0
  100. data/rails_app/rails_6.0/config/initializers/cors.rb +17 -0
  101. data/rails_app/rails_6.0/config/initializers/filter_parameter_logging.rb +6 -0
  102. data/rails_app/rails_6.0/config/initializers/inflections.rb +17 -0
  103. data/rails_app/rails_6.0/config/initializers/mime_types.rb +5 -0
  104. data/rails_app/rails_6.0/config/initializers/wrap_parameters.rb +11 -0
  105. data/rails_app/rails_6.0/config/locales/en.yml +33 -0
  106. data/rails_app/rails_6.0/config/routes.rb +5 -0
  107. data/rails_app/rails_6.0/config/spring.rb +8 -0
  108. data/rails_app/rails_6.0/public/robots.txt +1 -0
  109. data/rails_app/rails_6.0/spec/rails_helper.rb +14 -0
  110. data/rails_app/rails_6.0/spec/spec_helper.rb +13 -0
  111. metadata +81 -8
  112. data/gemfiles/rails_4.2.gemfile +0 -15
  113. 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
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- my_api_client (0.14.0)
5
- activesupport (>= 4.2.0)
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 (5.2.4.1)
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.0)
21
- bugsnag (6.13.0)
21
+ ast (2.4.1)
22
+ bugsnag (6.18.0)
22
23
  concurrent-ruby (~> 1.0)
23
- byebug (11.1.1)
24
- coderay (1.1.2)
25
- concurrent-ruby (1.1.6)
26
- crack (0.4.3)
27
- safe_yaml (~> 1.0.0)
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.0.0)
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.2)
34
+ i18n (1.8.5)
34
35
  concurrent-ruby (~> 1.0)
35
- jaro_winkler (1.5.4)
36
- json (2.3.0)
37
- jsonpath (1.0.5)
36
+ json (2.3.1)
37
+ jsonpath (1.0.6)
38
38
  multi_json
39
- to_regexp (~> 0.2.1)
40
- method_source (0.9.2)
41
- minitest (5.14.0)
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.19.1)
45
- parser (2.7.0.4)
46
- ast (~> 2.4.0)
47
- pry (0.12.2)
48
- coderay (~> 1.1.0)
49
- method_source (~> 0.9.0)
50
- pry-byebug (3.8.0)
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.10)
53
- public_suffix (4.0.3)
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.9.0)
58
- rspec-core (~> 3.9.0)
59
- rspec-expectations (~> 3.9.0)
60
- rspec-mocks (~> 3.9.0)
61
- rspec-core (3.9.1)
62
- rspec-support (~> 3.9.1)
63
- rspec-expectations (3.9.1)
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.9.0)
66
- rspec-mocks (3.9.1)
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.9.0)
69
- rspec-support (3.9.2)
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 (0.80.1)
73
- jaro_winkler (~> 1.5.1)
72
+ rubocop (1.5.1)
74
73
  parallel (~> 1.10)
75
- parser (>= 2.7.0.1)
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, < 1.7)
80
- rubocop-performance (1.5.2)
81
- rubocop (>= 0.71.0)
82
- rubocop-rspec (1.38.1)
83
- rubocop (>= 0.68.1)
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
- safe_yaml (1.0.5)
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
- to_regexp (0.2.1)
96
- tzinfo (1.2.6)
100
+ tzinfo (1.2.8)
97
101
  thread_safe (~> 0.1)
98
- unicode-display_width (1.6.1)
99
- webmock (3.8.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.24)
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.2
129
+ 2.1.4
@@ -6,12 +6,14 @@ MyApiClient は API リクエストクラスを作成するための汎用的な
6
6
 
7
7
  ただし、 Sawyer はダミーデータの作成が難しかったり、他の gem で競合することがよくあるので、将来的には依存しないように変更していくかもしれません。
8
8
 
9
- また、 Ruby on Rails で利用することを想定してますが、それ以外の環境でも動作するように作っているつもりです。不具合などあれば Issue ページからご報告下さい。
9
+ また、 Ruby on Rails で利用することを想定してますが、それ以外の環境でも動作するように作っています。不具合などあれば Issue ページからご報告下さい。
10
+
11
+ [toc]
10
12
 
11
13
  ## Supported Versions
12
14
 
13
- * Ruby 2.4, 2.5, 2.6, 2.7
14
- * Rails 4.2, 5.0, 5.1, 5.2, 6.0
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, raise: MyApiClient::ClientError
158
+ error_handling status_code: 400..499,
159
+ raise: MyApiClient::ClientError
95
160
 
96
- error_handling status_code: 500..599 do |params, logger|
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 }, with: :my_error_handling
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 req and res params
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` が指定可能です。`raise` には `MyApiClient::Error` を継承したクラスが指定可能です。`my_api_client` で標準で定義しているエラークラスについては以下のソースコードをご確認下さい。
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.rb
193
+ https://github.com/ryz310/my_api_client/blob/master/lib/my_api_client/errors
127
194
 
128
- 次に、 `raise` の代わりに `block` を指定する場合について。
195
+ 次に、 `block` を指定する場合について。
129
196
 
130
197
  ```ruby
131
- error_handling status_code: 500..599 do |params, logger|
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` にはインスタンスメソッド名を指定することで、エラーを検出した際に任意のメソッドを実行させることができます。メソッドに渡される引数は `block` 定義の場合と同じく `params` と `logger` です。
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
- ただし、 `ActiveJob` とは異なり同期処理でリトライするため、ネットワークの瞬断に備えたリトライ以外ではあまり使う機会はないのではないかと思います。上記の例のように API Limit に備えてリトライするケースもあるかと思いますが、こちらは `ActiveJob` で対応した方が良いと思います。
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: