chimera_http_client 0.4.0 → 0.5.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: f53a50a92fd82daebeae2cad2156dd5a0eef366d4aec27d2ecb13fffe8f771f3
4
- data.tar.gz: ef515b583ba8cbbd76286e626dfbe34cf06662710c04e441f9d4e926577962cb
3
+ metadata.gz: 5e2fa666cf4ec3fe21e1f4a8ecfb3932c5dac1cb6d0c7d16762eea73bf76fb44
4
+ data.tar.gz: df72864e42844dd77dcc9f64bfc23f69d73a66ee66f7589c8ef1e460524b831c
5
5
  SHA512:
6
- metadata.gz: fa715d6646f2f924a67bd0049598156eaacee8b60a81d28858cddf86f8a7e42c2ae50097fd7be824d8d7ff91fd0bc1569713cb014b7e3a1859a634bf9c3d4568
7
- data.tar.gz: '069987a5e71950ba299b313a93f9cb6533adfe275bbda057a076614aeb8d053fc1e574a7db588d75dfc36a7611d10260c6b0ebde9fac274474e5ef85603fe356'
6
+ metadata.gz: 52cd8916ab3bd1956753eac56a54a0c9b6130fdfbb38e9d7f2083b137097e1a585a8d205ad75f6e3b6713ee55cf66c1443b8136c22f7d48c8e0045da397612c5
7
+ data.tar.gz: 70f7a691115d59909ec1831d48ed1fc02f4aa7ce8057bc35cf015a4254ee1f09318b45a20cf30686548d2b0bd686644ac0df6f5f6e9e9c2303b09b5cedfbb611
data/.rubocop.yml CHANGED
@@ -76,6 +76,9 @@ Style/NumericLiterals:
76
76
  Style/Semicolon:
77
77
  AllowAsExpressionSeparator: true
78
78
 
79
+ Style/SymbolProc:
80
+ Enabled: false
81
+
79
82
  # Cop supports --auto-correct.
80
83
  # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
81
84
  # SupportedStyles: comma, consistent_comma, no_comma
data/README.markdown CHANGED
@@ -1,6 +1,10 @@
1
1
  # ChimeraHttpClient
2
2
 
3
- When starting to split monolithic apps into smaller services, you need an easy way to access the remote data from the other apps. This chimera_http_client gem should serve as a unified way to access endpoints from other apps. And what works for the internal communication between your own apps, will also work for external APIs that do not offer a client for simplified access.
3
+ When starting to split monolithic apps into smaller services, you need an easy way to access the remote data from the other apps. This **chimera_http_client gem** should serve as **a comfortable and unifying way** to access endpoints from other apps.
4
+
5
+ And what works for the internal communication between your own apps, will also work for external APIs that do not offer a client for simplified access.
6
+
7
+ It offers an **easy to learn interface** and **nice error handling**. And it enables you to **queue HTTP requests to run them in parallel** for better performance.
4
8
 
5
9
  ## Dependencies
6
10
 
@@ -8,10 +12,43 @@ The `chimera_http_client` gem is using the _libcurl_ wrapper [**Typhoeus**](http
8
12
 
9
13
  It does not have any other runtime dependencies.
10
14
 
11
- ### optional
15
+ ### ENV variables
12
16
 
13
17
  Setting the environment variable `ENV['CHIMERA_HTTP_CLIENT_LOG_REQUESTS']` to `true` (or `'true'`) will provide more detailed error messages for logging and also add additional information to the Error JSON. It is recommended to use this only in development environments.
14
18
 
19
+ ## Table of Contents
20
+
21
+ <!-- TOC depthFrom:1 depthTo:4 withLinks:1 updateOnSave:0 orderedList:0 -->
22
+
23
+ - [ChimeraHttpClient](#chimerahttpclient)
24
+ - [Table of Contents](#table-of-contents)
25
+ - [Dependencies](#dependencies)
26
+ - [ENV variables](#env-variables)
27
+ - [The Connection class](#the-connection-class)
28
+ - [Initialization](#initialization)
29
+ - [Mandatory initialization parameter `base_url`](#mandatory-initialization-parameter-baseurl)
30
+ - [Optional initialization parameters](#optional-initialization-parameters)
31
+ - [Request methods](#request-methods)
32
+ - [Mandatory request parameter `endpoint`](#mandatory-request-parameter-endpoint)
33
+ - [Optional request parameters](#optional-request-parameters)
34
+ - [Basic auth](#basic-auth)
35
+ - [Timeout duration](#timeout-duration)
36
+ - [Custom logger](#custom-logger)
37
+ - [Caching responses](#caching-responses)
38
+ - [Example usage](#example-usage)
39
+ - [The Request class](#the-request-class)
40
+ - [The Response class](#the-response-class)
41
+ - [Error classes](#error-classes)
42
+ - [The Queue class](#the-queue-class)
43
+ - [Queueing requests](#queueing-requests)
44
+ - [Executing requests in parallel](#executing-requests-in-parallel)
45
+ - [Installation](#installation)
46
+ - [Maintainers and Contributors](#maintainers-and-contributors)
47
+ - [Roadmap](#roadmap)
48
+ - [Chimera](#chimera)
49
+
50
+ <!-- /TOC -->
51
+
15
52
  ## The Connection class
16
53
 
17
54
  The basic usage looks like this:
@@ -21,38 +58,119 @@ connection = ChimeraHttpClient::Connection.new(base_url: 'http://localhost/names
21
58
  response = connection.get!(endpoint, params: params)
22
59
  ```
23
60
 
24
- `ChimeraHttpClient::Connection.new` expects an options hash as parameter. The only required option is **base_url** which should include the host, port and base path to the API endpoints you want to call, e.g.
25
- `base_url: 'http://localhost:3000/v1'`.
61
+ ### Initialization
62
+
63
+ `connection = ChimeraHttpClient::Connection.new(base_url: 'http://localhost:3000/v1', logger: logger, cache: cache)`
64
+
65
+ #### Mandatory initialization parameter `base_url`
66
+
67
+ The mandatory parameter is **base_url** which should include the host, port and base path to the API endpoints you want to call, e.g. `'http://localhost:3000/v1'`.
68
+
69
+ Setting the `base_url` is meant to be a comfort feature, as you can then pass short endpoints to each request like `/users`. You could set an empty string `''` as `base_url` and then pass full qualified URLs as endpoint of the requests.
70
+
71
+ #### Optional initialization parameters
26
72
 
27
- On this connection object, you can call methods like `#get!` or `#post!` with an endpoint and an options hash as parameters, e.g.
28
- `connection.get!("users/#{id}")`
29
- or
30
- `connection.get(['users', id], options: { headers: { ' Accept-Charset' => 'utf-8' })`
73
+ The optional parameters are:
31
74
 
32
- Please take note that _the endpoint can be given as a String, a Symbol, or as an Array._
33
- While they do no harm, there is _no need to pass leading or trailing `/` in endpoints._
34
- When passing the endpoint as an Array, _it's elements are converted to Strings and concatenated with `/`._
35
- On each request _the http-headers can be amended or overwritten_ completely or partially.
75
+ * `logger` - an instance of a logger class that implements `#info` and `#warn` methods
76
+ * `timeout` - the timeout for all requests, can be overwritten in any request, the default are 3 seconds
77
+ * `user_agent` - if you would like your calls to identify with a specific user agent
78
+ * `verbose` - the default is `false`, set it to true while debugging issues
79
+ * `cache` - an instance of your cache solution, can be overwritten in any request
36
80
 
37
- ### Basic auth
81
+ ### Request methods
82
+
83
+ The available methods are:
84
+
85
+ * `get` / `get!`
86
+ * `post` / `post!`
87
+ * `put` / `put`
88
+ * `patch` / `patch!`
89
+ * `delete` / `delete!`
90
+
91
+ where the methods ending on a _bang!_ will raise an error (which you should handle in your application) while the others will return an error object.
92
+
93
+ #### Mandatory request parameter `endpoint`
94
+
95
+ The `base_url` set in the connection will together with the `endpoint` determine the URL to make a request to.
96
+
97
+ ```ruby
98
+ connection.get([:users, id])
99
+ connection.get(["users", id])
100
+ connection.get("users/#{id}")
101
+ connection.get("/users/#{id}")
102
+ ```
38
103
 
39
- In case you need to use an API that is protected by **basic_auth** just pass the credentials in the options hash:
40
- `options: { username: 'admin', password: 'secret' }`
104
+ All forms above ave valid and will make a request to the same URL.
41
105
 
42
- ### Timeout duration
106
+ * Please take note that _the endpoint can be given as a String, a Symbol, or an Array._
107
+ * While they do no harm, there is _no need to pass leading or trailing `/` in endpoints._
108
+ * When passing the endpoint as an Array, _it's elements are converted to Strings and concatenated with `/`._
109
+
110
+ #### Optional request parameters
111
+
112
+ All request methods expect a mandatory `endpoint` and an optional hash as parameters. In the latter the following keywords are treated specially:
113
+
114
+ * `body` - the mandatory body of a `post`, `put` or `patch` request
115
+ * `headers` - a hash of HTTP headers
116
+ * `params` - parameters of a HTTP request
117
+ * `username` - used for a BasicAuth login
118
+ * `password` - used for a BasicAuth login
119
+ * `timeout` - set a custom timeout per request (the default is 3 seconds)
120
+ * `cache` - optionally overwrite the cache store set in `Connection` in any request
121
+
122
+ Example:
123
+
124
+ ```ruby
125
+ connection.post(
126
+ :users,
127
+ body: { name: "Andy" },
128
+ params: { origin: `Twitter`},
129
+ headers: { "Authorization" => "Bearer #{token}" },
130
+ timeout: 10,
131
+ cache: nil
132
+ )
133
+ ```
134
+
135
+ #### Basic auth
136
+
137
+ In case you need to use an API that is protected by **basic_auth** just pass the credentials as optional parameters:
138
+ `username: 'admin', password: 'secret'`
139
+
140
+ #### Timeout duration
43
141
 
44
142
  The default timeout duration is **3 seconds**.
45
143
 
46
144
  If you want to use a different timeout, you can pass the key `timeout` when initializing the `Connection`. You can also overwrite it on every call.
47
145
 
48
- ### Custom logger
146
+ #### Custom logger
49
147
 
50
148
  By default no logging is happening. If you need request logging, you can pass your custom Logger to the key `logger` when initializing the `Connection`. It will write to `logger.info` when starting and when completing a request.
51
149
 
52
- ### Caching responses
150
+ #### Caching responses
53
151
 
54
152
  To cache all the reponses of a connection, just pass the optional parameter `cache` to its initializer. You can also overwrite the connection's cache configuration by passing the parameter `cache` to any `get` call.
55
153
 
154
+ It could be an instance of an implementation as simple as this:
155
+
156
+ ```ruby
157
+ class Cache
158
+ def initialize
159
+ @memory = {}
160
+ end
161
+
162
+ def get(request)
163
+ @memory[request]
164
+ end
165
+
166
+ def set(request, response)
167
+ @memory[request] = response
168
+ end
169
+ end
170
+ ```
171
+
172
+ Or use an adapter for Dalli, Redis, or Rails cache that also support an optional time-to-live `default_ttl` parameter.
173
+
56
174
  Read more about how to use it: https://github.com/typhoeus/typhoeus#caching
57
175
 
58
176
  ### Example usage
@@ -180,6 +298,52 @@ The error classes and their corresponding http error codes:
180
298
  ServerError # 500..599
181
299
  TimeoutError # timeout
182
300
 
301
+ ## The Queue class
302
+
303
+ Instead of making single requests immediately, the ChimeraHttpClient allows to queue requests and run them in **parallel**.
304
+
305
+ The number of parallel requests is limited by your system. There is a hard limit for 200 concurrent requests. You will have to measure yourself where the sweet spot for optimal performance is - and when things start to get flaky. I recommend to queue not much more than 20 requests before running them.
306
+
307
+ ### Queueing requests
308
+
309
+ The initializer of the `Queue` class expects and handles the same parameters as the `Connection` class.
310
+
311
+ ```ruby
312
+ queue = ChimeraHttpClient::Queue.new(base_url: 'http://localhost:3000/v1')
313
+ ```
314
+
315
+ `queue.add` expects and handles the same parameters as the requests methods of a connection.
316
+
317
+ ```ruby
318
+ queue.add(method, endpoint, options = {})
319
+ ```
320
+
321
+ The only difference is that a parameter to set the HTTP method has to prepended. Valid options for `method` are:
322
+
323
+ * `:get` / `'get'` / `'GET'`
324
+ * `:post` / `'post'` / `'POST'`
325
+ * `:put` / `'put'` / `'PUT'`
326
+ * `:patch` / `'patch'` / `'PATCH'`
327
+ * `:delete` / `'delete'` / `'DELETE'`
328
+
329
+ ### Executing requests in parallel
330
+
331
+ Once the queue is filled, run all the requests concurrently with:
332
+
333
+ ```ruby
334
+ responses = queue.execute
335
+ ```
336
+
337
+ `responses` will contain an Array of `ChimeraHttpClient::Response` objects when all calls succeed. If any calls fail, the Array will also contain `ChimeraHttpClient::Error` objects. It is in your responsibility to handle the errors.
338
+
339
+ > Tip: every `Response` and every `Error` make the underlying `Typheous::Request` available over `object.response.request`, which could help with debugging, or with building your own retry mechanism.
340
+
341
+ ### Empty the queue
342
+
343
+ The queue is emptied after execution. You could also empty it at any other point before by calling `queue.empty`.
344
+
345
+ To inspect the requests waiting for execution, call `queue.queued_requests`.
346
+
183
347
  ## Installation
184
348
 
185
349
  Add this line to your application's Gemfile:
@@ -196,7 +360,7 @@ When updating the version, do not forget to run
196
360
 
197
361
  ## Maintainers and Contributors
198
362
 
199
- After checking out the repo, run `rake` to run the **tests and rubocop**.
363
+ After checking out the repo, run `bundle install` and then `bundle execute rake` to run the **tests and rubocop**.
200
364
 
201
365
  You can also run `rake console` to open an irb session with the `ChimeraHttpClient` pre-loaded that will allow you to experiment.
202
366
 
data/Rakefile CHANGED
@@ -5,7 +5,12 @@ RSpec::Core::RakeTask.new(:rspec)
5
5
 
6
6
  desc "Open a console with the ChimeraHttpClient loaded"
7
7
  task :console do
8
- system "irb -r lib/chimera_http_client.rb"
8
+ puts "Console with the gem and awesome_print loaded:"
9
+ ARGV.clear
10
+ require "irb"
11
+ require "ap"
12
+ load "lib/chimera_http_client.rb"
13
+ IRB.start
9
14
  end
10
15
 
11
16
  desc "Run Rubocop"
data/TODO.markdown CHANGED
@@ -15,11 +15,11 @@ _none known_
15
15
 
16
16
  ### Logger
17
17
 
18
- * ~allow to pass a logger~
19
- * ~add logger.info when starting a http call~
20
- * ~add logger.info when finishing a successful http call~
21
- * ~include the total_time of the requests in the log~
22
- * ~add (example) to README~
18
+ * ~~allow to pass a logger~~
19
+ * ~~add logger.info when starting a http call~~
20
+ * ~~add logger.info when finishing a successful http call~~
21
+ * ~~include the total_time of the requests in the log~~
22
+ * ~~add (example) to README~~
23
23
  * add logger.warn / .error for error cases (?)
24
24
 
25
25
  ### Custom Serializer
@@ -35,28 +35,46 @@ _none known_
35
35
  * use custom deserializer in #parsed_body instead of default JSON parsing
36
36
  * add example to README
37
37
 
38
- ### Queueing
38
+ ### Queueing / running in parallel
39
39
 
40
- * allow to queue multiple calls
41
- * execute (up to 10) calls in parallel
40
+ * ~~allow to queue multiple requests~~
41
+ * ~~execute (up to 200) requests in parallel~~
42
+ * allow to pass one proc / block (for all requests) to use as on_complete handler for each request
42
43
  * add example to README
43
44
 
44
- ### Caching
45
+ ### Queueing / run requests serialized
45
46
 
46
- * optional per connection or call
47
+ * allow to queue multiple requests
48
+ * execute (up to 5) queued requests
49
+ * allow to pass a proc (per request) to use the response for the next request
50
+ * or just explain how to code that yourself?
47
51
  * add example to README
48
52
 
53
+ ### Caching
54
+
55
+ * ~~optional per connection or call~~
56
+ * ~~add example to README~~
57
+
49
58
  ### Timeout
50
59
 
51
- * ~allow to set custom timeout per connection~
52
- * ~allow to set custom timeout per call~
53
- * ~add (example) to README~
60
+ * ~~allow to set custom timeout per connection~~
61
+ * ~~allow to set custom timeout per call~~
62
+ * ~~add (example) to README~~
54
63
 
55
64
  ### Release
56
65
 
57
- * ~rename module to have unique namespace~
58
- * ~release to rubygems to add to the plethora of similar gems~
59
- * ~make repo public~
66
+ * ~~rename module to have unique namespace~~
67
+ * ~~release to rubygems to add to the plethora of similar gems~~
68
+ * ~~make repo public~~
60
69
  * hook up Travis-CI
61
70
  * ensure it runs with Ruby 2.4 and newer
62
71
  * get feedback
72
+
73
+ ### File Uploads
74
+
75
+ * add example to README
76
+
77
+ ### Streaming response bodies
78
+
79
+ * enable to pass on_headers, on_body, on_complete procs
80
+ * add example to README
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_runtime_dependency "typhoeus", "~> 1.1"
22
22
 
23
+ spec.add_development_dependency "awesome_print", "~> 1.8"
23
24
  spec.add_development_dependency "bundler", "~> 1.13"
24
25
  spec.add_development_dependency "irb", "~> 1.0"
25
26
  spec.add_development_dependency "rake", ">= 10.0"
@@ -0,0 +1,54 @@
1
+ module ChimeraHttpClient
2
+ class Base
3
+ USER_AGENT = "ChimeraHttpClient (by mediafinger)".freeze
4
+
5
+ def initialize(base_url:, logger: nil, timeout: nil, user_agent: USER_AGENT, verbose: false, cache: nil)
6
+ fail(ChimeraHttpClient::ParameterMissingError, "base_url expected, but not given") if base_url.nil?
7
+
8
+ @base_url = base_url
9
+ @logger = logger
10
+ @timeout = timeout
11
+
12
+ Typhoeus::Config.user_agent = user_agent
13
+ Typhoeus::Config.verbose = verbose
14
+ Typhoeus::Config.memoize = false
15
+ Typhoeus::Config.cache = cache
16
+ end
17
+
18
+ private
19
+
20
+ # Add default values to call options
21
+ def augmented_options(options)
22
+ options[:timeout] ||= @timeout
23
+
24
+ options
25
+ end
26
+
27
+ def extract_body(options)
28
+ body = options.delete(:body)
29
+ body_optional = options.delete(:body_optional)
30
+ fail(ChimeraHttpClient::ParameterMissingError, "body expected, but not given") if body.nil? && !body_optional
31
+ body
32
+ end
33
+
34
+ def extract_headers(options, headers)
35
+ given_headers = options.delete(:headers) || {}
36
+ headers.merge(given_headers)
37
+ end
38
+
39
+ def default_headers
40
+ { "Content-Type" => "application/json" }
41
+ end
42
+
43
+ # Build URL out of @base_url and endpoint given as String or Array, while trimming redundant "/"
44
+ def url(endpoint)
45
+ trimmed_endpoint = Array(endpoint).map { |e| trim(e) }
46
+ [@base_url.chomp("/"), trimmed_endpoint].flatten.reject(&:empty?).join("/")
47
+ end
48
+
49
+ # Remove leading and trailing "/" from a give part of a String (usually URL or endpoint)
50
+ def trim(element)
51
+ element.to_s.sub(%r{^\/}, "").chomp("/")
52
+ end
53
+ end
54
+ end
@@ -2,22 +2,11 @@
2
2
  # The bang methods get!, post!, put!, patch! and delete! raise a Error in case of failure
3
3
 
4
4
  module ChimeraHttpClient
5
- class Connection
6
- USER_AGENT = "ChimeraHttpClient (by mediafinger)".freeze
7
-
8
- def initialize(base_url:, logger: nil, timeout: nil, user_agent: USER_AGENT, verbose: false, cache: nil)
9
- fail(ChimeraHttpClient::ParameterMissingError, "base_url expected, but not given") if base_url.nil?
10
-
11
- @base_url = base_url
12
- @logger = logger
13
- @timeout = timeout
5
+ class Connection < Base
6
+ def initialize(options = {})
7
+ super(options)
14
8
 
15
9
  define_bang_methods
16
-
17
- Typhoeus::Config.user_agent = user_agent
18
- Typhoeus::Config.verbose = verbose
19
- Typhoeus::Config.memoize = false
20
- Typhoeus::Config.cache = cache
21
10
  end
22
11
 
23
12
  def request
@@ -25,70 +14,34 @@ module ChimeraHttpClient
25
14
  end
26
15
 
27
16
  def get(endpoint, options = {})
28
- headers = extract_headers(options, default_headers)
29
-
30
- request.run(url: url(endpoint), method: :get, options: augmented_options(options), headers: headers)
17
+ run(:get, endpoint, options.merge(body_optional: true))
31
18
  end
32
19
 
33
20
  def post(endpoint, options = {})
34
- run_with_body(:post, endpoint, options)
21
+ run(:post, endpoint, options)
35
22
  end
36
23
 
37
24
  def put(endpoint, options = {})
38
- run_with_body(:put, endpoint, options)
25
+ run(:put, endpoint, options)
39
26
  end
40
27
 
41
28
  def patch(endpoint, options = {})
42
- run_with_body(:patch, endpoint, options)
29
+ run(:patch, endpoint, options)
43
30
  end
44
31
 
45
32
  def delete(endpoint, options = {})
46
- run_with_body(:delete, endpoint, options.merge(body_optional: true))
33
+ run(:delete, endpoint, options.merge(body_optional: true))
47
34
  end
48
35
 
49
36
  private
50
37
 
51
- # Add default values to call options
52
- def augmented_options(options)
53
- options[:timeout] ||= @timeout
54
-
55
- options
56
- end
57
-
58
- def run_with_body(method, endpoint, options = {})
38
+ def run(method, endpoint, options = {})
59
39
  body = extract_body(options)
60
40
  headers = extract_headers(options, default_headers)
61
41
 
62
42
  request.run(url: url(endpoint), method: method, body: body, options: augmented_options(options), headers: headers)
63
43
  end
64
44
 
65
- # Build URL out of @base_url and endpoint given as String or Array, while trimming redundant "/"
66
- def url(endpoint)
67
- trimmed_endpoint = Array(endpoint).map { |e| trim(e) }
68
- [@base_url.chomp("/"), trimmed_endpoint].flatten.reject(&:empty?).join("/")
69
- end
70
-
71
- # Remove leading and trailing "/" from a give part of a String (usually URL or endpoint)
72
- def trim(element)
73
- element.to_s.sub(%r{^\/}, "").chomp("/")
74
- end
75
-
76
- def extract_body(options)
77
- body = options.delete(:body)
78
- body_optional = options.delete(:body_optional)
79
- fail(ChimeraHttpClient::ParameterMissingError, "body expected, but not given") if body.nil? && !body_optional
80
- body
81
- end
82
-
83
- def extract_headers(options, headers)
84
- given_headers = options.delete(:headers) || {}
85
- headers.merge(given_headers)
86
- end
87
-
88
- def default_headers
89
- { "Content-Type" => "application/json" }
90
- end
91
-
92
45
  # get! post! put! patch! delete! return an Response when successful, but raise an Error otherwise
93
46
  def define_bang_methods
94
47
  {
@@ -0,0 +1,49 @@
1
+ module ChimeraHttpClient
2
+ class Queue < Base
3
+ def add(method, endpoint, options = {})
4
+ http_method = method.downcase.to_sym
5
+ options[:body_optional] = true if %i[get delete].include?(http_method)
6
+
7
+ body = extract_body(options)
8
+ headers = extract_headers(options, default_headers)
9
+
10
+ req = Request.new(logger: @logger).create(
11
+ url: url(endpoint),
12
+ method: http_method,
13
+ body: body,
14
+ options: augmented_options(options),
15
+ headers: headers
16
+ )
17
+
18
+ queued_requests << req
19
+ end
20
+
21
+ def execute
22
+ queued_requests.each do |request|
23
+ hydra.queue(request.request)
24
+ end
25
+
26
+ hydra.run
27
+
28
+ responses = queued_requests.map { |request| request.result }
29
+
30
+ empty
31
+
32
+ responses
33
+ end
34
+
35
+ def empty
36
+ @queued_requests = []
37
+ end
38
+
39
+ def queued_requests
40
+ @queued_requests ||= []
41
+ end
42
+
43
+ private
44
+
45
+ def hydra
46
+ @hydra ||= Typhoeus::Hydra.new
47
+ end
48
+ end
49
+ end
@@ -2,11 +2,21 @@ module ChimeraHttpClient
2
2
  class Request
3
3
  TIMEOUT_SECONDS = 3
4
4
 
5
+ attr_reader :request, :result
6
+
5
7
  def initialize(logger: nil)
6
8
  @logger = logger
7
9
  end
8
10
 
9
11
  def run(url:, method:, body: nil, options: {}, headers: {})
12
+ create(url: url, method: method, body: body, options: options, headers: headers)
13
+
14
+ @request.run
15
+
16
+ @result
17
+ end
18
+
19
+ def create(url:, method:, body: nil, options: {}, headers: {})
10
20
  request_params = {
11
21
  method: method,
12
22
  body: body,
@@ -22,20 +32,19 @@ module ChimeraHttpClient
22
32
  password = options.fetch(:password, nil)
23
33
  request_params[:userpwd] = "#{username}:#{password}" if username && password
24
34
 
25
- request = Typhoeus::Request.new(url, request_params)
35
+ @request = Typhoeus::Request.new(url, request_params)
26
36
 
27
- result = nil
28
- request.on_complete do |response|
37
+ @result = nil
38
+ @request.on_complete do |response|
29
39
  @logger&.info("Completed HTTP request: #{method.upcase} #{url} " \
30
40
  "in #{response.total_time&.round(3)}sec with status code #{response.code}")
31
41
 
32
- result = on_complete_handler(response)
42
+ @result = on_complete_handler(response)
33
43
  end
34
44
 
35
45
  @logger&.info("Starting HTTP request: #{method.upcase} #{url}")
36
- request.run
37
46
 
38
- result
47
+ self
39
48
  end
40
49
 
41
50
  private
@@ -1,3 +1,3 @@
1
1
  module ChimeraHttpClient
2
- VERSION = "0.4.0".freeze
2
+ VERSION = "0.5.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chimera_http_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Finger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-15 00:00:00.000000000 Z
11
+ date: 2019-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: awesome_print
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -126,8 +140,10 @@ files:
126
140
  - TODO.markdown
127
141
  - chimera_http_client.gemspec
128
142
  - lib/chimera_http_client.rb
143
+ - lib/chimera_http_client/base.rb
129
144
  - lib/chimera_http_client/connection.rb
130
145
  - lib/chimera_http_client/error.rb
146
+ - lib/chimera_http_client/queue.rb
131
147
  - lib/chimera_http_client/request.rb
132
148
  - lib/chimera_http_client/response.rb
133
149
  - lib/chimera_http_client/version.rb