my_api_client 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/Gemfile.lock +1 -1
- data/README.jp.md +76 -7
- data/lib/my_api_client/rspec.rb +8 -0
- data/lib/my_api_client/rspec/stub.rb +81 -0
- data/lib/my_api_client/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f79acd9dda7576ad4ef44c65c31d5c6fd4c3ebe64dc6ce8106bd81097931b84
|
4
|
+
data.tar.gz: ff17d603eabd348ff39e7c209e3fa601bcbaeee1a97beeda73e46b9c6d16eda4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3258a69b3e289f8277d307759aeca39ea14dd8f0573ef686cb5fb24625b7afe30d9be4e65fe896c7ca9ebdd25612c2fe07b980e72bcb8dfe63598c0297fe46d
|
7
|
+
data.tar.gz: 6cf8c1ee680e128f4ecfda474a528dc61323dba9ca592b7f044e5a9024a27eb6e8926cb4423909c7299198abca88d48aa127cb11d0b0f72d74e2e95c7310550d
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.jp.md
CHANGED
@@ -6,6 +6,11 @@ MyApiClient は API リクエストクラスを作成するための汎用的な
|
|
6
6
|
|
7
7
|
また、 Ruby on Rails で利用することを想定してますが、それ以外の環境でも動作するように作っているつもりです。不具合などあれば Issue ページからご報告下さい。
|
8
8
|
|
9
|
+
## Supported Versions
|
10
|
+
|
11
|
+
* Ruby 2.4, 2.5, 2.6
|
12
|
+
* Rails 4.2, 5.0, 5.1, 5.2
|
13
|
+
|
9
14
|
## Installation
|
10
15
|
|
11
16
|
この gem は macOS と Linux で作動します。まずは、my_api_client を Gemfile に追加します:
|
@@ -31,7 +36,7 @@ create spec/api_clients/path/to/resource_api_client_spec.rb
|
|
31
36
|
|
32
37
|
最もシンプルな利用例を以下に示します。
|
33
38
|
|
34
|
-
```
|
39
|
+
```ruby
|
35
40
|
class ExampleApiClient < MyApiClient::Base
|
36
41
|
endpoint 'https://example.com'
|
37
42
|
|
@@ -78,7 +83,7 @@ api_clinet.get_users #=> #<Sawyer::Response>
|
|
78
83
|
|
79
84
|
上記のコードにエラーハンドリングを追加してみます。
|
80
85
|
|
81
|
-
```
|
86
|
+
```ruby
|
82
87
|
class ExampleApiClient < MyApiClient::Base
|
83
88
|
endpoint 'https://example.com'
|
84
89
|
|
@@ -106,7 +111,7 @@ end
|
|
106
111
|
|
107
112
|
一つずつ解説していきます。まず、以下のように `status_code` を指定するものについて。
|
108
113
|
|
109
|
-
```
|
114
|
+
```ruby
|
110
115
|
error_handling status_code: 400..499, raise: MyApiClient::ClientError
|
111
116
|
```
|
112
117
|
|
@@ -118,7 +123,7 @@ https://github.com/ryz310/my_api_client/blob/master/lib/my_api_client/errors.rb
|
|
118
123
|
|
119
124
|
次に、 `raise` の代わりに Block を指定する場合について。
|
120
125
|
|
121
|
-
```
|
126
|
+
```ruby
|
122
127
|
error_handling status_code: 500..599 do |params, logger|
|
123
128
|
logger.warn 'Server error occurred.'
|
124
129
|
raise MyApiClient::ServerError, params
|
@@ -135,7 +140,7 @@ API request `GET https://example.com/path/to/resouce`: "Server error occurred."
|
|
135
140
|
|
136
141
|
最後に `json` と `with` を利用する場合について。
|
137
142
|
|
138
|
-
```
|
143
|
+
```ruby
|
139
144
|
error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
140
145
|
```
|
141
146
|
|
@@ -152,7 +157,7 @@ error_handling json: { '$.errors.code': 10..19 }, with: :my_error_handling
|
|
152
157
|
|
153
158
|
`with` にはインスタンスメソッド名を指定することで、エラーを検出した際に任意のメソッドを実行させることができます。メソッドに渡される引数は Block 定義の場合と同じく `params` と `logger` です。
|
154
159
|
|
155
|
-
```
|
160
|
+
```ruby
|
156
161
|
# @param params [MyApiClient::Params::Params] HTTP req and res params
|
157
162
|
# @param logger [MyApiClient::Logger] Logger for a request processing
|
158
163
|
def my_error_handling(params, logger)
|
@@ -173,7 +178,7 @@ WIP
|
|
173
178
|
|
174
179
|
多くの場合、同一ホストの API は リクエストヘッダーやエラー情報が同じ構造になっているため、上記のように一つのクラス内に複数の API を定義する設計が理にかなっていますが、 API 毎に個別に定義したい場合は、以下のように 1 つのクラスに 1 の API という構造で設計することも可能です。
|
175
180
|
|
176
|
-
```
|
181
|
+
```ruby
|
177
182
|
class ExampleApiClient < MyApiClient::Base
|
178
183
|
endpoint 'https://example.com'
|
179
184
|
|
@@ -227,6 +232,70 @@ WIP
|
|
227
232
|
|
228
233
|
WIP
|
229
234
|
|
235
|
+
### RSpec
|
236
|
+
|
237
|
+
RSpec を使ったテストをサポートしています。
|
238
|
+
以下のコードを `spec/spec_helper.rb` (または `spec/rails_helper.rb`) に追記して下さい。
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
require 'my_api_client/rspec'
|
242
|
+
```
|
243
|
+
|
244
|
+
例えば以下のような `ApiClient` を定義しているとします。
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
class ExampleApiClient < MyApiClient::Base
|
248
|
+
endpoint 'https://example.com'
|
249
|
+
|
250
|
+
def request(user_id:)
|
251
|
+
get "users/#{user_id}"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
```
|
255
|
+
|
256
|
+
`my_api_client_stub` を使うことで、 `ExampleApiClient#request` をスタブ化することができます。これで `#request` を実行してもリアルな HTTP リクエストが実行されなくなります。
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
my_api_client_stub(ExampleApiClient, :request, response: { id: 12345 })
|
260
|
+
|
261
|
+
response = ExampleApiClient.new.request(user_id: 1)
|
262
|
+
response.id # => 12345
|
263
|
+
```
|
264
|
+
|
265
|
+
リクスエストパラメータを使ったレスポンスを返すようにスタブ化したい場合は、 block を利用することで実現できます。
|
266
|
+
|
267
|
+
```ruby
|
268
|
+
my_api_client_stub(ExampleApiClient, :request) do |params|
|
269
|
+
{ id: params[:user_id] }
|
270
|
+
end
|
271
|
+
|
272
|
+
response = ExampleApiClient.new.request(user_id: 1)
|
273
|
+
response.id # => 1
|
274
|
+
```
|
275
|
+
|
276
|
+
`receive` や `have_received` を使ったテストを書きたい場合は、 `my_api_client_stub` の戻り値を利用すると良いでしょう。
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
def execute_api_request
|
280
|
+
ExampleApiClient.new.request(user_id: 1)
|
281
|
+
end
|
282
|
+
|
283
|
+
api_clinet = my_api_client_stub(ExampleApiClient, :request)
|
284
|
+
execute_api_request
|
285
|
+
expect(api_client).to have_received(:request).with(user_id: 1)
|
286
|
+
```
|
287
|
+
|
288
|
+
また、例外が発生する場合のテストを書きたい場合は、 `raise` オプションを利用することができます。
|
289
|
+
|
290
|
+
```ruby
|
291
|
+
def execute_api_request
|
292
|
+
ExampleApiClient.new.request(user_id: 1)
|
293
|
+
end
|
294
|
+
|
295
|
+
my_api_client_stub(ExampleApiClient, :request, raise: MyApiClient::Error)
|
296
|
+
expect { execute_api_request }.to raise_error(MyApiClient::Error)
|
297
|
+
```
|
298
|
+
|
230
299
|
## Contributing
|
231
300
|
|
232
301
|
不具合の報告や Pull Request を歓迎しています。OSS という事で自分はなるべく頑張って英語を使うようにしていますが、日本語での報告でも大丈夫です :+1:
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyApiClient
|
4
|
+
# Test helper module for RSpec
|
5
|
+
module Stub
|
6
|
+
# Provides stubbing feature for `MyApiClient`.
|
7
|
+
#
|
8
|
+
# @param klass [Class]
|
9
|
+
# Stubbing target class.
|
10
|
+
# @param action [Symbol]
|
11
|
+
# Stubbing target method name.
|
12
|
+
# @param response [Object, nil]
|
13
|
+
# Stubbed ApiClient will return parameters set by `response`.
|
14
|
+
# default: nil
|
15
|
+
# @param raise [Class, MyApiClient::Error, nil]
|
16
|
+
# Stubbed ApiClient will raise exception set by `raise`.
|
17
|
+
# You can set either exception class or exception instance.
|
18
|
+
# default: nil
|
19
|
+
# @return [InstanceDouble]
|
20
|
+
# Returns a spy object for the ApiClient.
|
21
|
+
# rubocop:disable Metrics/AbcSize
|
22
|
+
def my_api_client_stub(klass, action, response: nil, raise: nil)
|
23
|
+
instance = instance_double(klass)
|
24
|
+
allow(klass).to receive(:new).and_return(instance)
|
25
|
+
if raise.present?
|
26
|
+
allow(instance).to receive(action).and_raise(process_raise_option(raise))
|
27
|
+
elsif block_given?
|
28
|
+
allow(instance).to receive(action) { |*request| stub_as_sawyer(yield(*request)) }
|
29
|
+
else
|
30
|
+
allow(instance).to receive(action).and_return(stub_as_sawyer(response))
|
31
|
+
end
|
32
|
+
instance
|
33
|
+
end
|
34
|
+
# rubocop:enable Metrics/AbcSize
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# Provides a shorthand for `raise` option.
|
39
|
+
# `MyApiClient::Error` requires `MyApiClient::Params::Params` instance on
|
40
|
+
# initialize, but it makes trubolesome. `MyApiClient::NetworkError` is more.
|
41
|
+
# If given a error instance, it will return raw value without processing.
|
42
|
+
#
|
43
|
+
# @param exception [Clsas, MyApiClient::Error] Processing target.
|
44
|
+
# @return [MyApiClient::Error] Processed exception.
|
45
|
+
# @raise [RuntimeError] Unsupported error class was set.
|
46
|
+
def process_raise_option(exception)
|
47
|
+
case exception
|
48
|
+
when Class
|
49
|
+
params = instance_double(MyApiClient::Params::Params, to_bugsnag: {})
|
50
|
+
if exception == MyApiClient::NetworkError
|
51
|
+
exception.new(params, Net::OpenTimeout.new)
|
52
|
+
else
|
53
|
+
exception.new(params)
|
54
|
+
end
|
55
|
+
when MyApiClient::Error
|
56
|
+
exception
|
57
|
+
else
|
58
|
+
raise "Unsupported error class was set: #{exception.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def stub_as_sawyer(params)
|
63
|
+
case params
|
64
|
+
when Hash then Sawyer::Resource.new(agent, params)
|
65
|
+
when Array then params.map { |hash| sawyer_resource(hash) }
|
66
|
+
when nil then nil
|
67
|
+
else params
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def agent
|
72
|
+
instance_double('Sawyer::Agent').tap do |agent|
|
73
|
+
allow(agent).to receive(:parse_links) do |data|
|
74
|
+
data ||= {}
|
75
|
+
links = data.delete(:_links)
|
76
|
+
[data, links]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ryz310
|
@@ -264,6 +264,8 @@ files:
|
|
264
264
|
- lib/my_api_client/params/params.rb
|
265
265
|
- lib/my_api_client/params/request.rb
|
266
266
|
- lib/my_api_client/request.rb
|
267
|
+
- lib/my_api_client/rspec.rb
|
268
|
+
- lib/my_api_client/rspec/stub.rb
|
267
269
|
- lib/my_api_client/version.rb
|
268
270
|
- my_api_client.gemspec
|
269
271
|
homepage: https://github.com/ryz310/my_api_client
|