wrappi 0.2.1 → 0.2.2
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 +4 -4
- data/.travis.yml +7 -2
- data/README.md +260 -30
- data/lib/wrappi.rb +3 -0
- data/lib/wrappi/async_handler.rb +17 -0
- data/lib/wrappi/async_job.rb +51 -0
- data/lib/wrappi/client.rb +1 -4
- data/lib/wrappi/endpoint.rb +50 -27
- data/lib/wrappi/version.rb +1 -1
- data/wrappi.gemspec +8 -3
- metadata +16 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d76d08b4ea48473c331491f345bf3349020d2939038abab2df92c6b2ee39a159
|
|
4
|
+
data.tar.gz: c17875fe3958e459610c7996f285e493f50b589e053703a5a14aefd54c1061d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '03181ab50cbfeb1e55b408bf5d8fd11e919b9e6f6528ff0c4670b1296cac684fc67a0a29b376b292772cde316ed9cfe9a0e50475278c2a5da05946728afed817'
|
|
7
|
+
data.tar.gz: 289a464e32f98a82c0098e5372e96935377a8ec2c9da5c9f8d3f7c3e55bbc7d33542e51f7fe7c4b565b70fae787a1ee7186b1c95084ef6bb94bef31348f7f1e4
|
data/.travis.yml
CHANGED
|
@@ -7,11 +7,16 @@ rvm:
|
|
|
7
7
|
- 2.4.4
|
|
8
8
|
- 2.5.1
|
|
9
9
|
- ruby-head
|
|
10
|
+
matrix:
|
|
11
|
+
allow_failures:
|
|
12
|
+
- rvm: 2.3.7
|
|
13
|
+
- rvm: ruby-head
|
|
14
|
+
fast_finish: true
|
|
10
15
|
before_install:
|
|
11
16
|
- docker build -t dummy -f spec/dummy/Dockerfile .
|
|
12
|
-
- docker run -d -p 127.0.0.1:9873:9873 dummy
|
|
17
|
+
- docker run -d -p 127.0.0.1:9873:9873 dummy /bin/sh -c "bin/rails server -b 0.0.0.0 -p 9873"
|
|
13
18
|
- docker ps -a
|
|
14
|
-
- gem install bundler
|
|
19
|
+
- gem install bundler
|
|
15
20
|
script:
|
|
16
21
|
- bundle exec rspec
|
|
17
22
|
# Code climate test reporter
|
data/README.md
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
[](https://codeclimate.com/github/arturictus/wrappi/test_coverage)
|
|
4
4
|
|
|
5
5
|
# Wrappi
|
|
6
|
+
Making APIs fun again!
|
|
6
7
|
|
|
7
|
-
Framework to create API clients.
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Wrappi is a Framework to create API clients. The intention is to bring the best practices and standardize how API clients behave.
|
|
9
|
+
It allows to create API clients in a declarative way improving readability and unifying the behavior. It abstracts complex operations like caching, retries background requests and error handling.
|
|
10
|
+
|
|
11
|
+
Enjoy!
|
|
10
12
|
|
|
11
13
|
## Installation
|
|
12
14
|
|
|
@@ -29,7 +31,7 @@ Or install it yourself as:
|
|
|
29
31
|
__Github example:__
|
|
30
32
|
|
|
31
33
|
```ruby
|
|
32
|
-
module
|
|
34
|
+
module GithubAPI
|
|
33
35
|
class Client < Wrappi::Client
|
|
34
36
|
setup do |config|
|
|
35
37
|
config.domain = 'https://api.github.com'
|
|
@@ -49,13 +51,191 @@ end
|
|
|
49
51
|
```
|
|
50
52
|
|
|
51
53
|
```ruby
|
|
52
|
-
user =
|
|
54
|
+
user = GithubAPI::User.new(username: 'arturictus')
|
|
53
55
|
user.success? # => true
|
|
54
56
|
user.error? # => false
|
|
55
57
|
user.status_code # => 200
|
|
56
58
|
user.body # => {"login"=>"arturictus", "id"=>1930175, ...}
|
|
57
59
|
```
|
|
58
60
|
|
|
61
|
+
#### Async
|
|
62
|
+
Wrappi comes with a background Job out of the box. If you are in a Rails app the `#async`
|
|
63
|
+
method will queue a new job (`< ActiveJob::Base`) that will make the request and trigger the async callback
|
|
64
|
+
after the request is made.
|
|
65
|
+
|
|
66
|
+
example:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
class User < Wrappi::Endpoint
|
|
70
|
+
client Client
|
|
71
|
+
verb :get
|
|
72
|
+
path "users/:username"
|
|
73
|
+
async_callback do |opts|
|
|
74
|
+
# this will be called in background after the request is made
|
|
75
|
+
if success?
|
|
76
|
+
if opts[:create]
|
|
77
|
+
CreateUserService.call(body)
|
|
78
|
+
elsif opts[:update]
|
|
79
|
+
UpdateUserService.call(body)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
# This will execute the request in a background job
|
|
85
|
+
Github::User.new(username: 'arturictus').async(create: true)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If you need to send options to your Job (the `::set` method) you can pass the key `set`
|
|
89
|
+
to the options.
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
Github::User.new(username: 'arturictus').async(create: true, set: { wait: 10.minutes })
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Cache
|
|
96
|
+
You can enable cache per endpoint.
|
|
97
|
+
|
|
98
|
+
Set the cache Handler in your client.
|
|
99
|
+
It must behave like `Rails.cache` and respond to:
|
|
100
|
+
- `read([key])`
|
|
101
|
+
- `write([key, value, options])`
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
class Client < Wrappi::Client
|
|
105
|
+
setup do |config|
|
|
106
|
+
config.domain = 'https://api.github.com'
|
|
107
|
+
config.cache = Rails.cache
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Enable cache in your endpoint.
|
|
113
|
+
```ruby
|
|
114
|
+
class User < Wrappi::Endpoint
|
|
115
|
+
cache true # enable for endpoint
|
|
116
|
+
client Client
|
|
117
|
+
verb :get
|
|
118
|
+
path "users/:username"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
user = User.new(username: 'arturictus')
|
|
122
|
+
user.response.class # => Wrappi::Response
|
|
123
|
+
user.flush
|
|
124
|
+
user.response.class # => Wrappi::CachedResponse
|
|
125
|
+
user.success? # => true
|
|
126
|
+
user.body # => {"login"=>"arturictus", "id"=>1930175, ...}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
When cached the response will be a `Wrappi::CachedResponse`. `Wrappi::CachedResponse` behaves
|
|
130
|
+
like `Wrappi::Response` that means you can use the endpoint in the same way as it was a non cached.
|
|
131
|
+
See `cache_options` to fine tune your cache with expiration and other cache options.
|
|
132
|
+
|
|
133
|
+
You can use options to cache a single request.
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
class User < Wrappi::Endpoint
|
|
137
|
+
client Client
|
|
138
|
+
verb :get
|
|
139
|
+
path "users/:username"
|
|
140
|
+
end
|
|
141
|
+
User.new({username: 'arturictus'}, cache: true)
|
|
142
|
+
user.response.class # => Wrappi::Response
|
|
143
|
+
user.flush
|
|
144
|
+
user.response.class # => Wrappi::CachedResponse
|
|
145
|
+
user.success? # => true
|
|
146
|
+
user.body # => {"login"=>"arturictus", "id"=>1930175, ...}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Retry
|
|
150
|
+
Sometimes you want to retry if certain conditions affected your request.
|
|
151
|
+
|
|
152
|
+
This will retry if status code is not `200`
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
class User < Wrappi::Endpoint
|
|
156
|
+
client Client
|
|
157
|
+
verb :get
|
|
158
|
+
path "users/:username"
|
|
159
|
+
retry_if do |response, endpoint|
|
|
160
|
+
endpoint.status_code != 200
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Check more configuration options and examples for `retry_if` and `retry_options` below.
|
|
166
|
+
|
|
167
|
+
#### Flexibility
|
|
168
|
+
|
|
169
|
+
__options:__
|
|
170
|
+
|
|
171
|
+
Pass a second argument with options.
|
|
172
|
+
```ruby
|
|
173
|
+
params = { username: 'arturictus' }
|
|
174
|
+
options = { options_in_my_instance: "yeah!" }
|
|
175
|
+
|
|
176
|
+
User.new(params, options)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
__Dynamic configurations:__
|
|
180
|
+
|
|
181
|
+
All the configs in `Endpoint` are evaluated at instance level except: `around_request` and `retry_if` because of their nature.
|
|
182
|
+
That allows you to fine tune the configuration at a instance level.
|
|
183
|
+
|
|
184
|
+
example:
|
|
185
|
+
|
|
186
|
+
Right now the default for `cache` config is: `proc { options[:cache] }`.
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
class User < Wrappi::Endpoint
|
|
190
|
+
client Client
|
|
191
|
+
verb :get
|
|
192
|
+
path "users/:username"
|
|
193
|
+
cache do
|
|
194
|
+
if input_params[:username] == 'arturictus'
|
|
195
|
+
false
|
|
196
|
+
else
|
|
197
|
+
options[:cache]
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
__endpoint is a ruby class:__ :open_mouth:
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
class User < Wrappi::Endpoint
|
|
209
|
+
client Client
|
|
210
|
+
verb :get
|
|
211
|
+
path "users/:username"
|
|
212
|
+
cache do
|
|
213
|
+
cache?
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def cache?
|
|
217
|
+
if input_params[:username] == 'arturictus'
|
|
218
|
+
false
|
|
219
|
+
else
|
|
220
|
+
options[:cache]
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def parsed_response
|
|
225
|
+
@parsed_response ||= MyParser.new(body)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
__inheritance:__
|
|
231
|
+
All the configs will be inherited
|
|
232
|
+
|
|
233
|
+
```ruby
|
|
234
|
+
class UserDetail < User
|
|
235
|
+
path "users/:username/detail"
|
|
236
|
+
end
|
|
237
|
+
```
|
|
238
|
+
|
|
59
239
|
### Configurations
|
|
60
240
|
|
|
61
241
|
#### Client
|
|
@@ -64,28 +244,32 @@ user.body # => {"login"=>"arturictus", "id"=>1930175, ...}
|
|
|
64
244
|
|-----------------|--------------------------|--------------------------------------------------------------------------|----------|
|
|
65
245
|
| domain | String | | * |
|
|
66
246
|
| params | Hash | | |
|
|
67
|
-
| logger | Logger | Logger.new(STDOUT) | |
|
|
68
247
|
| headers | Hash | { 'Content-Type' => 'application/json', 'Accept' => 'application/json' } | |
|
|
69
|
-
|
|
|
248
|
+
| async_handler | const | Wrappi::AsyncHandler | |
|
|
249
|
+
| cache | const | | |
|
|
250
|
+
| logger | Logger | Logger.new(STDOUT) | |
|
|
251
|
+
| timeout | Hash | { write: 9, connect: 9, read: 9 } | |
|
|
70
252
|
| use_ssl_context | Boolean | false | |
|
|
253
|
+
| ssl_context | OpenSSL::SSL::SSLContext | | |
|
|
71
254
|
|
|
72
255
|
#### Endpoint
|
|
73
256
|
|
|
74
|
-
| Name | Type
|
|
75
|
-
|
|
76
|
-
| client | Wrappi::Client
|
|
77
|
-
| path | String
|
|
78
|
-
| verb | Symbol
|
|
79
|
-
| default_params | Hash
|
|
80
|
-
| headers | Hash
|
|
81
|
-
| basic_auth | Hash (keys: user, pass)
|
|
82
|
-
| follow_redirects | Boolean
|
|
83
|
-
| body_type | Symbol, one of: :json,:form,:body
|
|
84
|
-
| cache | Boolean
|
|
85
|
-
| cache_options | Hash
|
|
86
|
-
| retry_if | block
|
|
87
|
-
| retry_options | Hash
|
|
88
|
-
| around_request | block
|
|
257
|
+
| Name | Type | Default | Required |
|
|
258
|
+
|------------------|--------------------------------------------|-------------------------|----------|
|
|
259
|
+
| client | Wrappi::Client | | * |
|
|
260
|
+
| path | String | | * |
|
|
261
|
+
| verb | Symbol | :get | * |
|
|
262
|
+
| default_params | Hash `or` block -> Hash | {} | |
|
|
263
|
+
| headers | Hash `or` block -> Hash | proc { client.headers } | |
|
|
264
|
+
| basic_auth | Hash (keys: user, pass) `or` block -> Hash | | |
|
|
265
|
+
| follow_redirects | Boolean `or` block -> Boolean | true | |
|
|
266
|
+
| body_type | Symbol, one of: :json,:form,:body | :json | |
|
|
267
|
+
| cache | Boolean `or` block -> Boolean | proc { options[:cache] }| |
|
|
268
|
+
| cache_options | Hash `or` block -> Hash | | |
|
|
269
|
+
| retry_if | block | | |
|
|
270
|
+
| retry_options | Hash `or` block -> Hash | | |
|
|
271
|
+
| around_request | block | | |
|
|
272
|
+
| async_callback | block | | |
|
|
89
273
|
|
|
90
274
|
### Client
|
|
91
275
|
|
|
@@ -129,6 +313,42 @@ It holds the common configuration for all the endpoints (`Wrappi::Endpoint`).
|
|
|
129
313
|
"Auth-Token" => "verysecret"
|
|
130
314
|
}
|
|
131
315
|
```
|
|
316
|
+
- __async_handler:__ If you are not in Rails app or you have another background mechanism in place
|
|
317
|
+
you can configure here how the requests will be send to the background.
|
|
318
|
+
When `#async` is called on an Endpoint instance the `async_handler` const will be called with:
|
|
319
|
+
current endpoint instance (`self`) and the options passed to the async method.
|
|
320
|
+
```ruby
|
|
321
|
+
class MyAsyncHandler
|
|
322
|
+
def self.call(endpoint, opts)
|
|
323
|
+
# send to background
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
class Client < Wrappi::Client
|
|
327
|
+
setup do |config|
|
|
328
|
+
config.domain = 'https://api.github.com'
|
|
329
|
+
config.async_handler = MyAsyncHandler
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
endpoint_inst.async(this_opts_are_for_the_handler: true)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
- __timeout:__ Set your specific timout. When you set timeout it will be merged with defaults.
|
|
336
|
+
|
|
337
|
+
default: `{ write: 9, connect: 9, read: 9 }`
|
|
338
|
+
|
|
339
|
+
```ruby
|
|
340
|
+
class Client < Wrappi::Client
|
|
341
|
+
setup do |config|
|
|
342
|
+
config.domain = 'https://api.github.com'
|
|
343
|
+
config.timeout = { read: 3 }
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
Client.timeout # => { write: 9, connect: 9, read: 3 }
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
- __use_ssl_context:__ It has to be set to `true` for using the `ssl_context`
|
|
350
|
+
|
|
351
|
+
default: `false`
|
|
132
352
|
|
|
133
353
|
- __ssl_context:__ If you need to set an ssl_context.
|
|
134
354
|
|
|
@@ -139,10 +359,6 @@ It holds the common configuration for all the endpoints (`Wrappi::Endpoint`).
|
|
|
139
359
|
end
|
|
140
360
|
```
|
|
141
361
|
|
|
142
|
-
- __use_ssl_context:__ It has to be set to `true` for using the `ssl_context`
|
|
143
|
-
|
|
144
|
-
default: `false`
|
|
145
|
-
|
|
146
362
|
### Endpoint
|
|
147
363
|
|
|
148
364
|
#### Required:
|
|
@@ -224,7 +440,7 @@ It holds the common configuration for all the endpoints (`Wrappi::Endpoint`).
|
|
|
224
440
|
end
|
|
225
441
|
```
|
|
226
442
|
|
|
227
|
-
- __follow_redirects:__ If
|
|
443
|
+
- __follow_redirects:__ If the request responds with a redirection it will follow them.
|
|
228
444
|
|
|
229
445
|
default: `true`
|
|
230
446
|
|
|
@@ -236,6 +452,21 @@ It holds the common configuration for all the endpoints (`Wrappi::Endpoint`).
|
|
|
236
452
|
- :form
|
|
237
453
|
- :body (Binary data)
|
|
238
454
|
|
|
455
|
+
- __async_callback:__ When request is executed in the background with `#async(opts = {})` this
|
|
456
|
+
callback will be called with this opts as and argument in the block.
|
|
457
|
+
The block is executed in the endpoint instance. You can access to all the methods in Endpoint.
|
|
458
|
+
|
|
459
|
+
default: `proc {}`
|
|
460
|
+
|
|
461
|
+
```ruby
|
|
462
|
+
async_callback do |opts|
|
|
463
|
+
if success?
|
|
464
|
+
MyCreationService.call(body) if opts[:create]
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
MyEndpoint.new().async(create: true)
|
|
468
|
+
```
|
|
469
|
+
|
|
239
470
|
#### Flow Control:
|
|
240
471
|
|
|
241
472
|
This configs allows you fine tune your request adding middleware, retries and cache.
|
|
@@ -249,7 +480,7 @@ It holds the common configuration for all the endpoints (`Wrappi::Endpoint`).
|
|
|
249
480
|
|
|
250
481
|
- __cache:__ Cache the request if successful.
|
|
251
482
|
|
|
252
|
-
default: `
|
|
483
|
+
default: `proc { options[:cache] }`
|
|
253
484
|
- __cache_options:__ Options for the `cache` to receive on `write`
|
|
254
485
|
```ruby
|
|
255
486
|
cache_options expires_in: 12, another_opt: true
|
|
@@ -300,11 +531,10 @@ It holds the common configuration for all the endpoints (`Wrappi::Endpoint`).
|
|
|
300
531
|
|
|
301
532
|
After checking out the repo, run `bin/setup` to install dependencies.
|
|
302
533
|
|
|
303
|
-
Run test:
|
|
304
534
|
```
|
|
305
535
|
bin/dev_server
|
|
306
536
|
```
|
|
307
|
-
This will run a rails server. The test are running
|
|
537
|
+
This will run a rails server. The test are running against it.
|
|
308
538
|
|
|
309
539
|
```
|
|
310
540
|
bundle exec rspec
|
data/lib/wrappi.rb
CHANGED
|
@@ -7,8 +7,11 @@ require 'retryable'
|
|
|
7
7
|
module Wrappi
|
|
8
8
|
class TimeoutError < StandardError; end
|
|
9
9
|
class NotAuthorizedAccessError < StandardError; end
|
|
10
|
+
class JsonParseError < StandardError; end
|
|
10
11
|
end
|
|
11
12
|
|
|
13
|
+
require 'wrappi/async_job'
|
|
14
|
+
require 'wrappi/async_handler'
|
|
12
15
|
require 'wrappi/client'
|
|
13
16
|
require 'wrappi/executer'
|
|
14
17
|
require 'wrappi/endpoint'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Wrappi
|
|
2
|
+
class AsyncHandler
|
|
3
|
+
def self.call(*args)
|
|
4
|
+
new(*args).call
|
|
5
|
+
end
|
|
6
|
+
attr_reader :endpoint, :options
|
|
7
|
+
def initialize(endpoint, options)
|
|
8
|
+
@endpoint = endpoint
|
|
9
|
+
@options = options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
AsyncJob.set((options[:set] || {}))
|
|
14
|
+
.perform_later(endpoint.class.to_s, { params: endpoint.input_params, options: endpoint.options }, options)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Wrappi
|
|
2
|
+
module AsyncConcern
|
|
3
|
+
def wrappi_perform(endpoint_class, args, options)
|
|
4
|
+
@endpoint_class = endpoint_class
|
|
5
|
+
@args = parse(args)
|
|
6
|
+
@options = parse(options)
|
|
7
|
+
return unless endpoint_const
|
|
8
|
+
inst = endpoint_const.new(@args[:params], @args[:options])
|
|
9
|
+
inst.perform_async_callback(@options)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def parse(data)
|
|
15
|
+
return ia(data) if data.is_a?(Hash)
|
|
16
|
+
ia(JSON.parse(data)) rescue {}
|
|
17
|
+
rescue
|
|
18
|
+
data
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ia(data)
|
|
22
|
+
Fusu::HashWithIndifferentAccess.new(data)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def endpoint_const
|
|
26
|
+
Class.const_get(@endpoint_class)
|
|
27
|
+
rescue
|
|
28
|
+
puts "[Wrappi] Unable to find const #{@endpoint_class} for async"
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
if defined?(ActiveJob)
|
|
33
|
+
class Async < ActiveJob::Base
|
|
34
|
+
include AsyncConcern
|
|
35
|
+
def perform(*args)
|
|
36
|
+
wrappi_perform(*args)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
else
|
|
40
|
+
class AsyncJob
|
|
41
|
+
include AsyncConcern
|
|
42
|
+
def self.set(options = {})
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
def self.perform_later(*args)
|
|
46
|
+
puts "Unable to perform async ActiveJob is not installed"
|
|
47
|
+
new().wrappi_perform(*args)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/wrappi/client.rb
CHANGED
|
@@ -2,10 +2,6 @@ require 'logger'
|
|
|
2
2
|
module Wrappi
|
|
3
3
|
# This class is expected to handle all the configurations for your main module
|
|
4
4
|
class Client
|
|
5
|
-
class TimeoutError < StandardError; end
|
|
6
|
-
class JsonParseError < StandardError; end
|
|
7
|
-
class NotAuthorizedAccessError < StandardError; end
|
|
8
|
-
|
|
9
5
|
include Fusu::Configurable
|
|
10
6
|
|
|
11
7
|
# Not verify example
|
|
@@ -21,6 +17,7 @@ module Wrappi
|
|
|
21
17
|
end
|
|
22
18
|
config_accessor(:params) { {} }
|
|
23
19
|
config_accessor(:cache)
|
|
20
|
+
config_accessor(:async_handler) { AsyncHandler }
|
|
24
21
|
|
|
25
22
|
def self.setup
|
|
26
23
|
yield(self)
|
data/lib/wrappi/endpoint.rb
CHANGED
|
@@ -4,6 +4,7 @@ module Wrappi
|
|
|
4
4
|
:verb, :client, :path, :default_params,
|
|
5
5
|
:headers, :follow_redirects, :basic_auth,
|
|
6
6
|
:body_type, :retry_options, :cache, :cache_options,
|
|
7
|
+
:async_callback,
|
|
7
8
|
default_config: {
|
|
8
9
|
verb: :get,
|
|
9
10
|
client: proc { raise 'client not set' }, # TODO: add proper error
|
|
@@ -12,8 +13,9 @@ module Wrappi
|
|
|
12
13
|
headers: proc { client.headers },
|
|
13
14
|
follow_redirects: true,
|
|
14
15
|
body_type: :json,
|
|
15
|
-
cache:
|
|
16
|
-
cache_options: {}
|
|
16
|
+
cache: proc { options[:cache] },
|
|
17
|
+
cache_options: {},
|
|
18
|
+
async_callback: proc {}
|
|
17
19
|
}
|
|
18
20
|
)
|
|
19
21
|
attr_reader :input_params, :options
|
|
@@ -26,18 +28,19 @@ module Wrappi
|
|
|
26
28
|
new(*args).call
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
+
def response
|
|
32
|
+
@response ||= Executer.call(self)
|
|
31
33
|
end
|
|
34
|
+
alias_method :call, :response
|
|
32
35
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
def body; response.body end
|
|
37
|
+
def success?; response.success? end
|
|
38
|
+
def status; response.status end
|
|
39
|
+
def error?; !success? end
|
|
40
|
+
def flush; @response = nil end
|
|
41
|
+
|
|
42
|
+
def async(async_options = {})
|
|
43
|
+
async_handler.call(self, async_options)
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
# overridable
|
|
@@ -45,42 +48,62 @@ module Wrappi
|
|
|
45
48
|
params
|
|
46
49
|
end
|
|
47
50
|
|
|
48
|
-
def
|
|
49
|
-
|
|
51
|
+
def url
|
|
52
|
+
_url.to_s
|
|
50
53
|
end
|
|
51
|
-
alias_method :call, :response
|
|
52
54
|
|
|
53
|
-
def
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
def url_with_params
|
|
56
|
+
return url unless verb == :get
|
|
57
|
+
_url.tap do |u|
|
|
58
|
+
u.query = URI.encode_www_form(consummated_params) if consummated_params.any?
|
|
59
|
+
end.to_s
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def self.async_callback(&block)
|
|
64
|
+
@async_callback = block
|
|
65
|
+
end
|
|
56
66
|
|
|
57
|
-
# AROUND REQUEST
|
|
58
67
|
def self.around_request(&block)
|
|
59
68
|
@around_request = block
|
|
60
69
|
end
|
|
61
|
-
def around_request
|
|
62
|
-
self.class.instance_variable_get(:@around_request)
|
|
63
|
-
end
|
|
64
70
|
|
|
65
|
-
# RETRY
|
|
66
71
|
def self.retry_if(&block)
|
|
67
72
|
@retry_if = block
|
|
68
73
|
end
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
|
|
75
|
+
def perform_async_callback(async_options = {})
|
|
76
|
+
instance_exec(async_options, &async_callback)
|
|
71
77
|
end
|
|
72
78
|
|
|
73
|
-
# Cache
|
|
74
79
|
def cache_key
|
|
75
80
|
# TODO: think headers have to be in the key as well
|
|
76
81
|
@cache_key ||= "[#{verb.to_s.upcase}]##{url}#{params_cache_key}"
|
|
77
82
|
end
|
|
78
83
|
|
|
84
|
+
def around_request
|
|
85
|
+
self.class.instance_variable_get(:@around_request)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def retry_if
|
|
89
|
+
self.class.instance_variable_get(:@retry_if)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def async_callback
|
|
95
|
+
self.class.instance_variable_get(:@async_callback) || proc {}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
|
|
79
99
|
def logger
|
|
80
100
|
client.logger
|
|
81
101
|
end
|
|
82
102
|
|
|
83
|
-
|
|
103
|
+
# Overridable
|
|
104
|
+
def async_handler
|
|
105
|
+
client.async_handler
|
|
106
|
+
end
|
|
84
107
|
|
|
85
108
|
def params_cache_key
|
|
86
109
|
return if params.empty?
|
data/lib/wrappi/version.rb
CHANGED
data/wrappi.gemspec
CHANGED
|
@@ -9,8 +9,13 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.authors = ["Artur Pañach"]
|
|
10
10
|
spec.email = ["arturictus@gmail.com"]
|
|
11
11
|
|
|
12
|
-
spec.summary = %q{
|
|
13
|
-
spec.description = %q{Framework to create
|
|
12
|
+
spec.summary = %q{Making APIs fun again!}
|
|
13
|
+
spec.description = %q{Wrappi is a Framework to create API clients.
|
|
14
|
+
The intention is to bring the best practices and standardize how API clients behave.
|
|
15
|
+
It allows to create API clients in a declarative way improving readability and unifying the behavior.
|
|
16
|
+
It abstracts complex operations like caching, retries, background request and error handling.
|
|
17
|
+
|
|
18
|
+
Enjoy!}
|
|
14
19
|
spec.homepage = "https://github.com/arturictus/wrappi"
|
|
15
20
|
spec.license = "MIT"
|
|
16
21
|
|
|
@@ -19,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
|
19
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
20
25
|
spec.require_paths = ["lib"]
|
|
21
26
|
|
|
22
|
-
spec.add_development_dependency "bundler"
|
|
27
|
+
spec.add_development_dependency "bundler"
|
|
23
28
|
spec.add_development_dependency "rake", "~> 10.0"
|
|
24
29
|
spec.add_development_dependency "rspec", "~> 3.0"
|
|
25
30
|
spec.add_development_dependency "sinatra"
|
metadata
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: wrappi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Artur Pañach
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-02-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '0'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -122,8 +122,13 @@ dependencies:
|
|
|
122
122
|
- - ">="
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
124
|
version: '0'
|
|
125
|
-
description:
|
|
126
|
-
|
|
125
|
+
description: |-
|
|
126
|
+
Wrappi is a Framework to create API clients.
|
|
127
|
+
The intention is to bring the best practices and standardize how API clients behave.
|
|
128
|
+
It allows to create API clients in a declarative way improving readability and unifying the behavior.
|
|
129
|
+
It abstracts complex operations like caching, retries, background request and error handling.
|
|
130
|
+
|
|
131
|
+
Enjoy!
|
|
127
132
|
email:
|
|
128
133
|
- arturictus@gmail.com
|
|
129
134
|
executables: []
|
|
@@ -142,6 +147,8 @@ files:
|
|
|
142
147
|
- bin/dev_server
|
|
143
148
|
- bin/setup
|
|
144
149
|
- lib/wrappi.rb
|
|
150
|
+
- lib/wrappi/async_handler.rb
|
|
151
|
+
- lib/wrappi/async_job.rb
|
|
145
152
|
- lib/wrappi/cached_response.rb
|
|
146
153
|
- lib/wrappi/client.rb
|
|
147
154
|
- lib/wrappi/endpoint.rb
|
|
@@ -180,5 +187,5 @@ rubyforge_project:
|
|
|
180
187
|
rubygems_version: 2.7.6
|
|
181
188
|
signing_key:
|
|
182
189
|
specification_version: 4
|
|
183
|
-
summary:
|
|
190
|
+
summary: Making APIs fun again!
|
|
184
191
|
test_files: []
|