wrappi 0.1.2 → 0.2.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.
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