wrappi 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49b4ecb9e1cd6395c2e514f607da4460deda743f7e9eab24a786df41f674cef7
4
- data.tar.gz: 5e4b65bc43c871285b10268389ccba2df572a7083a21afe8bb6d5b93d4aeae7f
3
+ metadata.gz: 244907ad87d770e992be773f840eedaa08e370cc1b08f66981e13f45b12c4e30
4
+ data.tar.gz: 5024e8339f63640f24008f221288f3ee79805b8e80ac9d54980967390188ad66
5
5
  SHA512:
6
- metadata.gz: 57abcc813f5e80d1ec60fd665f05a4f18b9ef2048a75fbccae24870ab61177fad170b85c8492dfcaa3887ff07fd325ebc003839b780a15362288e0bd53a0bd39
7
- data.tar.gz: fda078035d91096d8bc6443157da9969ea597e2a608caed83a46f89551430dfa7962353d3ca9c8d4b8608076067aba501bd89e0d8e9591a4d308b14f2310ca94
6
+ metadata.gz: 2a655cb94421b1e9901ed275ca23a243ecce04e6afb97f24c34ff726f081bad2e8170657064c8a309f0271da46982a451759cc1be61212a52b62e2d284718651
7
+ data.tar.gz: 1cc627f259122b2c75ed6f239bb31676e8cb9a4e42c34fd23a5968f6a5373b4128da6cddc3fec52c5cec08c9e9f5e2bb0532aba540010004ee4b95e2265214f6
@@ -1,5 +1,26 @@
1
- sudo: false
2
1
  language: ruby
2
+ cache: bundler
3
+ services:
4
+ - docker
3
5
  rvm:
4
- - 2.1.6
5
- before_install: gem install bundler -v 1.12.4
6
+ - 2.3.7
7
+ - 2.4.4
8
+ - 2.5.1
9
+ - ruby-head
10
+ before_install:
11
+ - docker build -t dummy -f spec/dummy/Dockerfile .
12
+ - docker run -d -p 127.0.0.1:9873:9873 dummy
13
+ - docker ps -a
14
+ - gem install bundler -v 1.17.3
15
+ script:
16
+ - bundle exec rspec
17
+ # Code climate test reporter
18
+ env:
19
+ global:
20
+ - CC_TEST_REPORTER_ID=6cebf6c67b6e2d8a53a608ea98ebd897f4cba357bf1e3431bfdb77ff4207399e
21
+ before_script:
22
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
23
+ - chmod +x ./cc-test-reporter
24
+ - ./cc-test-reporter before-build
25
+ after_script:
26
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'fusu', path: '../fusu'
4
3
  # Specify your gem's dependencies in wrappi.gemspec
5
4
  gemspec
6
5
  gem 'pry'
6
+ gem 'cache_mock'
data/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ [![Build Status](https://travis-ci.org/arturictus/wrappi.svg?branch=master)](https://travis-ci.org/arturictus/wrappi)
2
+ [![Maintainability](https://api.codeclimate.com/v1/badges/8751a0b6523a52b5e23e/maintainability)](https://codeclimate.com/github/arturictus/wrappi/maintainability)
3
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/8751a0b6523a52b5e23e/test_coverage)](https://codeclimate.com/github/arturictus/wrappi/test_coverage)
4
+
1
5
  # Wrappi
2
6
 
3
7
  Framework to create API clients.
@@ -46,43 +50,77 @@ end
46
50
 
47
51
  ```ruby
48
52
  user = Github::User.new(username: 'arturictus')
49
- user.success?
50
- # => true
51
- user.code
52
- # => 200
53
- user.body
54
- # => {"login"=>"arturictus", "id"=>1930175, ...}
53
+ user.success? # => true
54
+ user.error? # => false
55
+ user.status_code # => 200
56
+ user.body # => {"login"=>"arturictus", "id"=>1930175, ...}
55
57
  ```
56
58
 
59
+ ### Configurations
60
+
61
+ #### Client
62
+
63
+ | Name | Type | Default | Required |
64
+ |-----------------|--------------------------|--------------------------------------------------------------------------|----------|
65
+ | domain | String | | * |
66
+ | params | Hash | | |
67
+ | logger | Logger | Logger.new(STDOUT) | |
68
+ | headers | Hash | { 'Content-Type' => 'application/json', 'Accept' => 'application/json' } | |
69
+ | ssl_context | OpenSSL::SSL::SSLContext | | |
70
+ | use_ssl_context | Boolean | false | |
71
+
72
+ #### Endpoint
73
+
74
+ | Name | Type | Default | Required |
75
+ |------------------|-----------------------------------|-------------------------|----------|
76
+ | client | Wrappi::Client | | * |
77
+ | path | String | | * |
78
+ | verb | Symbol | :get | * |
79
+ | default_params | Hash | {} | |
80
+ | headers | block | proc { client.headers } | |
81
+ | basic_auth | Hash, keys: user, pass | | |
82
+ | follow_redirects | Boolean | true | |
83
+ | body_type | Symbol, one of: :json,:form,:body | :json | |
84
+ | cache | Boolean | false | |
85
+ | retry_if | block | | |
86
+ | retry_options | block | | |
87
+ | around_request | block | | |
88
+
57
89
  ### Client
58
90
 
59
91
  Is the main configuration for your service.
60
92
 
61
93
  It holds the common configuration for all the endpoints (`Wrappi::Endpoint`).
62
94
 
63
- Required:
95
+ #### Required:
64
96
 
65
- - `domain`: Yep, you know.
97
+ - __domain:__ Yep, you know.
66
98
  ```ruby
67
99
  config.domain = 'https://api.github.com'
68
100
  ```
69
101
 
70
- Optionals:
102
+ #### Optionals:
71
103
 
72
- - `params`: Set global params for all the `Endpoints`.
104
+ - __params:__ Set global params for all the `Endpoints`.
73
105
  This is a great place to put the `api_key`.
74
106
  ```ruby
75
107
  config.params = { "api_key" => "asdfasdfoerkwlejrwer" }
76
108
  ```
77
109
  default: `{}`
78
110
 
79
- - `logger`: Set your logger.
111
+ - __logger:__ Set your logger.
112
+
113
+ default: `Logger.new(STDOUT)`
80
114
  ```ruby
81
115
  config.logger = Rails.logger
82
116
  ```
83
- default: `Logger.new(STDOUT)`
84
117
 
85
- - `headers`: Headers for all the endpoints. Format, Authentication.
118
+ - __headers:__ Headers for all the endpoints. Format, Authentication.
119
+
120
+ default:
121
+ ```ruby
122
+ { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
123
+ ```
86
124
  ```ruby
87
125
  config.headers = {
88
126
  "Content-Type" => "application/json",
@@ -90,57 +128,167 @@ Optionals:
90
128
  "Auth-Token" => "verysecret"
91
129
  }
92
130
  ```
93
- default:
94
- ```ruby
95
- { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
96
- ```
97
131
 
98
- - `ssl_context`: If you need to set an ssl_context.
132
+ - __ssl_context:__ If you need to set an ssl_context.
133
+
134
+ default: `nil`
99
135
  ```ruby
100
136
  config.ssl_context = OpenSSL::SSL::SSLContext.new.tap do |ctx|
101
137
  ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
102
138
  end
103
139
  ```
104
- default: `nil`
105
140
 
106
- - `use_ssl_context`: It has to be set to `true` for using the `ssl_context`
141
+ - __use_ssl_context:__ It has to be set to `true` for using the `ssl_context`
107
142
 
108
143
  default: `false`
109
144
 
110
145
  ### Endpoint
111
146
 
112
- Required:
113
- - `client`: `Wrappi::Client` `class`
114
- - `path`: The path.
147
+ #### Required:
148
+ - __client:__ `Wrappi::Client` `class`
149
+ ```ruby
150
+ client MyClient
151
+ ```
152
+
153
+ - __path:__ The path to the resource.
154
+ You can use doted notation and they will be interpolated with the params
155
+
156
+ ```ruby
157
+ class MyEndpoint < Wrappi::Endpoint
158
+ client MyClient
159
+ verb :get
160
+ path "/users/:id"
161
+ end
162
+ endpoint = MyEndpoint.new(id: "the_id", other: "foo")
163
+ endpoint.url_with_params #=> "http://domain.com/users/the_id?other=foo"
164
+ endpoint.url #=> "http://domain.com/users/the_id"
165
+ endpoint.consummated_params #=> {"other"=>"foo"}
166
+ ```
167
+ Notice how interpolated params are removed from the query or the body
168
+
169
+ - __verb:__
115
170
 
116
- TODO
117
- - `verb`:
171
+ default: `:get`
118
172
  - `:get`
119
173
  - `:post`
120
174
  - `:delete`
121
175
  - `:put`
122
176
 
123
- default: `:get`
124
177
 
125
- Optional:
178
+ #### Optional:
126
179
 
127
- - `default_params`:
180
+ - __default_params:__ Default params for the request. This params will be added
181
+ to all the instances unless you override them.
128
182
 
129
183
  default: `{}`
130
- - `headers`:
184
+
185
+ ```ruby
186
+ class MyEndpoint < Wrappi::Endpoint
187
+ client MyClient
188
+ verb :get
189
+ path "/users/:id"
190
+ default_params do
191
+ { other: "bar", foo: "foo" }
192
+ end
193
+ end
194
+ endpoint = MyEndpoint.new(id: "the_id", other: "foo")
195
+ endpoint.consummated_params #=> {"other"=>"foo","foo" => "foo" }
196
+ ```
197
+
198
+ - __headers:__ You can modify the client headers here. Notice that if you want
199
+ to use the client headers as well you will have to merge them.
131
200
 
132
201
  default: `proc { client.headers }`
202
+ ```ruby
203
+ class MyEndpoint < Wrappi::Endpoint
204
+ client MyClient
205
+ verb :get
206
+ path "/users"
207
+ headers do
208
+ client.headers #=> { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
209
+ client.headers.merge('Agent' => 'wrappi')
210
+ end
211
+ end
212
+ endpoint = MyEndpoint.new()
213
+ endpoint.headers #=> { 'Agent' => 'wrappi', 'Content-Type' => 'application/json', 'Accept' => 'application/json'}
214
+ ```
133
215
 
134
- - `basic_auth`:
216
+ - __basic_auth:__ If your endpoint requires basic_auth here is the place. keys
217
+ have to be: `user` and `pass`.
135
218
 
136
219
  default: `nil`
137
- - `follow_redirects`:
220
+ ```ruby
221
+ basic_auth do
222
+ { user: 'wrappi', pass: 'secret'}
223
+ end
224
+ ```
225
+
226
+ - __follow_redirects:__ If first request responds a redirect it will follow them.
138
227
 
139
228
  default: `true`
140
- - `body_type`:
229
+
230
+ - __body_type:__ Body type.
141
231
 
142
232
  default: `:json`
143
233
 
234
+ - :json
235
+ - :form
236
+ - :body (Binary data)
237
+
238
+ #### Flow Control:
239
+
240
+ This configs allows you fine tune your request adding middleware, retries and cache.
241
+ The are executed in this nested stack:
242
+ ```
243
+ cache
244
+ |- retry
245
+ |- around_request
246
+ ```
247
+ Check [specs](/blob/master/spec/wrappi/executer_spec.rb) for more examples.
248
+
249
+ - __cache:__ Cache the request if successful.
250
+
251
+ default: `false`
252
+ - __retry_if:__ Block to evaluate if request has to be retried. In the block are
253
+ yielded `Response` and `Endpoint` instances. If the block returns `true` the request will be retried.
254
+ ```ruby
255
+ retry_if do |response, endpoint|
256
+ endpoint.class #=> MyEndpoint
257
+ response.error? # => true or false
258
+ end
259
+ ```
260
+
261
+ Use case:
262
+
263
+ We have a service that returns an aggregation of hotels available to book for a city. The service will start the aggregation in the background and will return `200` if the aggregation is completed if the aggregation is not completed will return `201` making us know that we should call again to retrieve all the data. This behavior only occurs if we pass the param: `onlyIfComplete`.
264
+
265
+ ```ruby
266
+ retry_if do |response, endpoint|
267
+ endpoint.consummated_params["onlyIfComplete"] &&
268
+ response.status_code == 201
269
+ end
270
+ ```
271
+ Notice that this block will never be executed if an error occur (like timeouts). For retrying on errors use the `retry_options`
272
+
273
+ - __retry_options:__ We are using the great gem [retryable](https://github.com/nfedyashev/retryable) to accomplish this behavior.
274
+ Check the documentation for fine tuning. I just paste some examples for convenience.
275
+
276
+ ```ruby
277
+ retry_options do
278
+ { tries: 5, on: [ArgumentError, Wrappi::TimeoutError] } # or
279
+ { tries: :infinite, sleep: 0 }
280
+ end
281
+ ```
282
+ - __around_request:__ This block is executed surrounding the request. The request
283
+ will only get executed if you call `request.call`.
284
+ ```ruby
285
+ around_request do |request, endpoint|
286
+ endpoint.logger.info("making a request to #{endpoint.url} with params: #{endpoint.consummated_params}")
287
+ request.call # IMPORTANT
288
+ endpoint.logger.info("response status is: #{request.status_code}")
289
+ end
290
+ ```
291
+
144
292
  ## Development
145
293
 
146
294
  After checking out the repo, run `bin/setup` to install dependencies.
@@ -157,7 +305,17 @@ bundle exec rspec
157
305
 
158
306
  You can also run `bin/console` for an interactive prompt that will allow you to experiment.
159
307
 
308
+ #### Docker
160
309
 
310
+ Run dummy server with docker:
311
+ ```
312
+ docker build -t wrappi/dummy -f spec/dummy/Dockerfile .
313
+ docker run -d -p 127.0.0.1:9873:9873 wrappy/dummy /bin/sh -c "bin/rails server -b 0.0.0.0 -p 9873"
314
+ ```
315
+ Try:
316
+ ```
317
+ curl 127.0.0.1:9873 #=> {"controller":"pages","action":"show_body"}
318
+ ```
161
319
 
162
320
  ## Contributing
163
321
 
@@ -2,12 +2,17 @@ require "wrappi/version"
2
2
  require 'http'
3
3
  require 'fusu'
4
4
  require 'miller'
5
+ require 'retryable'
5
6
 
6
7
  module Wrappi
7
- # Your code goes here...
8
+ class TimeoutError < StandardError; end
9
+ class NotAuthorizedAccessError < StandardError; end
8
10
  end
9
11
 
10
12
  require 'wrappi/client'
13
+ require 'wrappi/executer'
11
14
  require 'wrappi/endpoint'
12
15
  require 'wrappi/request'
13
16
  require 'wrappi/path_gen'
17
+ require 'wrappi/uncalled_request'
18
+ require 'wrappi/cached_response'
@@ -0,0 +1,52 @@
1
+ module Wrappi
2
+ class CachedResponse
3
+ # input is a <Response>.to_h
4
+ # Example input
5
+ # {
6
+ # raw_body: '{"foo": "bar"}',
7
+ # code: 200,
8
+ # uri: "http://hello.com",
9
+ # success: true
10
+ # }
11
+ def initialize(cached_data)
12
+ @cached_data = Fusu::HashWithIndifferentAccess.new(cached_data)
13
+ end
14
+
15
+ def call
16
+ self
17
+ end
18
+
19
+ def called?
20
+ false
21
+ end
22
+
23
+ def body
24
+ @body ||= JSON.parse(cached_data[:raw_body])
25
+ end
26
+
27
+ def success?
28
+ cached_data[:success]
29
+ end
30
+
31
+ def error?
32
+ !success?
33
+ end
34
+
35
+ def raw_body
36
+ cached_data[:raw_body]
37
+ end
38
+
39
+ def uri
40
+ cached_data[:uri]
41
+ end
42
+
43
+ def status
44
+ cached_data[:code]
45
+ end
46
+ alias_method :status_code, :status
47
+
48
+ private
49
+
50
+ def cached_data; @cached_data end
51
+ end
52
+ end
@@ -20,6 +20,7 @@ module Wrappi
20
20
  'Accept' => 'application/json' }
21
21
  end
22
22
  config_accessor(:params) { {} }
23
+ config_accessor(:cache)
23
24
 
24
25
  def self.setup
25
26
  yield(self)
@@ -3,7 +3,7 @@ module Wrappi
3
3
  class Endpoint < Miller.base(
4
4
  :verb, :client, :path, :default_params,
5
5
  :headers, :follow_redirects, :basic_auth,
6
- :body_type,
6
+ :body_type, :retry_options, :cache,
7
7
  default_config: {
8
8
  verb: :get,
9
9
  client: proc { raise 'client not set' }, # TODO: add proper error
@@ -11,7 +11,8 @@ module Wrappi
11
11
  default_params: {},
12
12
  headers: proc { client.headers },
13
13
  follow_redirects: true,
14
- body_type: :json
14
+ body_type: :json,
15
+ cache: false
15
16
  }
16
17
  )
17
18
  attr_reader :input_params, :options
@@ -43,23 +44,8 @@ module Wrappi
43
44
  params
44
45
  end
45
46
 
46
- # overridable
47
- def before_request
48
- true
49
- end
50
-
51
- # overridable
52
- def after_request(response)
53
- true
54
- end
55
-
56
47
  def response
57
- return unless before_request
58
- @response ||= Response.new do
59
- Request.new(self).call
60
- end.tap(&:request)
61
- after_request(@response)
62
- @response
48
+ @response ||= Executer.call(self)
63
49
  end
64
50
  alias_method :call, :response
65
51
 
@@ -67,10 +53,42 @@ module Wrappi
67
53
  def success?; response.success? end
68
54
  def status; response.status end
69
55
 
56
+ # AROUND REQUEST
57
+ def self.around_request(&block)
58
+ @around_request = block
59
+ end
60
+ def around_request
61
+ self.class.instance_variable_get(:@around_request)
62
+ end
63
+
64
+ # RETRY
65
+ def self.retry_if(&block)
66
+ @retry_if = block
67
+ end
68
+ def retry_if
69
+ self.class.instance_variable_get(:@retry_if)
70
+ end
71
+
72
+ # Cache
73
+ def cache_key
74
+ # TODO: think headers have to be in the key as well
75
+ @cache_key ||= "[#{verb.to_s.upcase}]##{url}#{params_cache_key}"
76
+ end
77
+
78
+ def logger
79
+ client.logger
80
+ end
81
+
70
82
  private
71
83
 
84
+ def params_cache_key
85
+ return if params.empty?
86
+ d = Digest::MD5.hexdigest params.to_json
87
+ "?#{d}"
88
+ end
89
+
72
90
  def _url
73
- URI.join("#{client.domain}/", path_gen.path)
91
+ URI.join("#{client.domain}/", path_gen.path) # TODO: remove heading "/" of path
74
92
  end
75
93
 
76
94
  def params
@@ -0,0 +1,49 @@
1
+ module Wrappi
2
+ class Executer
3
+
4
+ def self.call(*args)
5
+ new(*args).call
6
+ end
7
+
8
+ attr_reader :endpoint, :retryer, :cacher
9
+ def initialize(endpoint)
10
+ @endpoint = endpoint
11
+ @retryer = Retryer.new(endpoint)
12
+ @cacher = Cacher.new(endpoint)
13
+ end
14
+
15
+ def call
16
+ if cache?
17
+ cacher.call do
18
+ request_with_retry
19
+ end
20
+ else
21
+ request_with_retry
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def cache?
28
+ cacher.cache?
29
+ end
30
+
31
+ def request_with_retry
32
+ retryer.call do
33
+ make_request
34
+ end
35
+ end
36
+
37
+ def around_request
38
+ endpoint.around_request || proc { |res, endpoint| res.call }
39
+ end
40
+
41
+ def make_request
42
+ res = Response.new { Request.new(endpoint).call }
43
+ around_request.call(res, endpoint)
44
+ res.called? ? res : UncalledRequest.new
45
+ end
46
+ end
47
+ end
48
+ require 'wrappi/executer/retryer'
49
+ require 'wrappi/executer/cacher'
@@ -0,0 +1,40 @@
1
+ module Wrappi
2
+ class Executer
3
+ class Cacher
4
+ attr_reader :endpoint
5
+ def initialize(endpoint)
6
+ @endpoint = endpoint
7
+ end
8
+
9
+ def call
10
+ cached = cache.read(cache_key)
11
+ return CachedResponse.new(cached) if cached
12
+ response = yield
13
+ cache.write(cache_key, response.to_h) if response.success?
14
+ response
15
+ end
16
+
17
+ def cache?
18
+ endpoint.client.cache && endpoint.cache && cache_allowed_verb?
19
+ end
20
+
21
+ def cache_allowed_verb?
22
+ if [:get, :post].include?(endpoint.verb)
23
+ true
24
+ else
25
+ puts "Cache is only available to no side effect requests: :get and :post" # TODO: make a warning
26
+ false
27
+ end
28
+ end
29
+
30
+ def cache
31
+ endpoint.client.cache
32
+ end
33
+
34
+ def cache_key
35
+ endpoint.cache_key
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,46 @@
1
+ module Wrappi
2
+ class Executer
3
+ class Retryer
4
+ class RetryError < StandardError; end
5
+ attr_reader :endpoint
6
+ def initialize(endpoint)
7
+ @endpoint = endpoint
8
+ end
9
+
10
+ def call
11
+ if retry?
12
+ Retryable.retryable(retry_options) do
13
+ res = yield
14
+ raise RetryError if retry_if.call(res, endpoint)
15
+ res
16
+ end
17
+ else
18
+ yield
19
+ end
20
+ end
21
+
22
+ def retry_options
23
+ default = { tries: 3, on: [RetryError] }
24
+ if endpoint.retry_options
25
+ end_opts = endpoint.retry_options.dup
26
+ {}.tap do |h|
27
+ h[:tries] = end_opts[:tries] || default[:tries]
28
+ if on = end_opts.delete(:on)
29
+ h[:on] = default[:on] + Fusu::Array.wrap(on)
30
+ end
31
+ end.merge(end_opts)
32
+ else
33
+ default
34
+ end
35
+ end
36
+
37
+ def retry?
38
+ !!endpoint.retry_if
39
+ end
40
+
41
+ def retry_if
42
+ endpoint.retry_if
43
+ end
44
+ end
45
+ end
46
+ end
@@ -23,6 +23,15 @@ module Wrappi
23
23
  def call
24
24
  @call ||= strategy.call
25
25
  end
26
+ alias_method :http, :call
27
+
28
+ def to_h
29
+ @to_h ||= {
30
+ raw_body: http.raw_body,
31
+ code: http.code,
32
+ uri: http.uri
33
+ }
34
+ end
26
35
  end
27
36
  end
28
37
  require 'wrappi/request/template'
@@ -3,10 +3,8 @@ module Wrappi
3
3
  # check documentation at:
4
4
  # https://github.com/httprb/http/wiki/Response-Handling
5
5
  class Response
6
- class TimeoutError < StandardError; end
7
- class NotAuthorizedAccessError < StandardError; end
8
- attr_reader :block
9
6
 
7
+ attr_reader :block
10
8
  def initialize(&block)
11
9
  @block = block
12
10
  end
@@ -17,6 +15,10 @@ module Wrappi
17
15
  end
18
16
  alias_method :call, :request
19
17
 
18
+ def called?
19
+ !!@request
20
+ end
21
+
20
22
  def body
21
23
  @body ||= request.parse
22
24
  end
@@ -40,6 +42,16 @@ module Wrappi
40
42
  def status
41
43
  request.code
42
44
  end
45
+ alias_method :status_code, :status
46
+
47
+ def to_h
48
+ @to_h ||= {
49
+ raw_body: raw_body,
50
+ code: code,
51
+ uri: uri,
52
+ success: success?
53
+ }
54
+ end
43
55
 
44
56
  def method_missing(method_name, *arguments, &block)
45
57
  if request.respond_to?(method_name)
@@ -0,0 +1,36 @@
1
+ module Wrappi
2
+ class UncalledRequest
3
+ def request
4
+ nil
5
+ end
6
+ alias_method :call, :request
7
+
8
+ def called?
9
+ true
10
+ end
11
+
12
+ def body
13
+ { "message" => "uncalled response" }
14
+ end
15
+
16
+ def success?
17
+ false
18
+ end
19
+
20
+ def error?
21
+ true
22
+ end
23
+
24
+ def raw_body
25
+ body.to_json
26
+ end
27
+
28
+ def uri
29
+ 'uncalled_response'
30
+ end
31
+
32
+ def status
33
+ 100
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,3 @@
1
1
  module Wrappi
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["arturictus@gmail.com"]
11
11
 
12
12
  spec.summary = %q{Framework to create HTTP API clients}
13
- spec.description = %q{Framework to create HTTP API clients abstracting the best practices and improving readability to your code.}
13
+ spec.description = %q{Framework to create HTTP API clients. The aim is to abstract the best practices using a declarative interface.}
14
14
  spec.homepage = "https://github.com/arturictus/wrappi"
15
15
  spec.license = "MIT"
16
16
 
@@ -26,4 +26,5 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency 'http', "~> 2.2"
27
27
  spec.add_dependency 'fusu', "~> 0.2.1"
28
28
  spec.add_dependency 'miller', "~> 0.1.1"
29
+ spec.add_dependency 'retryable'
29
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wrappi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
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-01-18 00:00:00.000000000 Z
11
+ date: 2019-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,8 +108,22 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: 0.1.1
111
- description: Framework to create HTTP API clients abstracting the best practices and
112
- improving readability to your code.
111
+ - !ruby/object:Gem::Dependency
112
+ name: retryable
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Framework to create HTTP API clients. The aim is to abstract the best
126
+ practices using a declarative interface.
113
127
  email:
114
128
  - arturictus@gmail.com
115
129
  executables: []
@@ -128,14 +142,19 @@ files:
128
142
  - bin/dev_server
129
143
  - bin/setup
130
144
  - lib/wrappi.rb
145
+ - lib/wrappi/cached_response.rb
131
146
  - lib/wrappi/client.rb
132
147
  - lib/wrappi/endpoint.rb
148
+ - lib/wrappi/executer.rb
149
+ - lib/wrappi/executer/cacher.rb
150
+ - lib/wrappi/executer/retryer.rb
133
151
  - lib/wrappi/path_gen.rb
134
152
  - lib/wrappi/request.rb
135
153
  - lib/wrappi/request/get.rb
136
154
  - lib/wrappi/request/template.rb
137
155
  - lib/wrappi/request/with_body.rb
138
156
  - lib/wrappi/response.rb
157
+ - lib/wrappi/uncalled_request.rb
139
158
  - lib/wrappi/version.rb
140
159
  - wrappi.gemspec
141
160
  homepage: https://github.com/arturictus/wrappi