chimera_http_client 1.0.0 → 1.1.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: 1a58fb6d4a20a8a2bef43186a46663abc494844ccc30cf6f2e467dd043519861
4
- data.tar.gz: '08c871044cb14bfbe9de820547ec7531a2719302f30d84e8aa9d658ed9ebf197'
3
+ metadata.gz: 01402cd235d413d16acc9adb72267b7a244898b5913d14d07e039ad6b1bd830b
4
+ data.tar.gz: 3909459cb620e544da67ee5864f39ab7ea51a6c33b6dd1b3fcddda5a56ec4dd5
5
5
  SHA512:
6
- metadata.gz: 28b48b1d2fe9b723a9b567b30be1dabdd2bdc76313f9392e4ebe30bf3a8568f729a00f7b0dbdc362099196dd5aea62ddfcceb09db15481b67ada604271a75546
7
- data.tar.gz: c211bc5978a7623c8f9ddaf1a069bd4f7d0aeb8bd680b2c8e61e6f9e4b32b281768da1b3bfa364b6ef69382763ae2f03324b37fa54d5277b1ae68e1468bc5b73
6
+ metadata.gz: 655127ba58b327eb2bc9f2ff6342ad3c93bd84c9cfa08fc262a4628005643e2562ae76ee68378331a92edb11cd9fb91fe0cf942f45d4ce911f176bfae8392c02
7
+ data.tar.gz: b3b282c08dc802b187ee95e974deb996ee833d3350f86ef4d6c89818ef1b182bedee2f043aaad50f392157829559b18b579480d7d50beef154617bb744e6cf9e
data/.travis.yml CHANGED
@@ -4,7 +4,6 @@ rvm:
4
4
  - ruby-head
5
5
  - 2.6
6
6
  - 2.5
7
- - 2.4
8
7
  - jruby
9
8
  - truffleruby
10
9
 
data/README.markdown CHANGED
@@ -14,7 +14,13 @@ The `chimera_http_client` gem is wrapping the **libcurl** wrapper [**Typhoeus**]
14
14
 
15
15
  The only other runtime dependency is Ruby's latest code loader [**zeitwerk**](https://github.com/fxn/zeitwerk) which is also part of Rails 6.
16
16
 
17
- All Ruby versions newer than **2.4** are supported.
17
+ ### Ruby version
18
+
19
+ | Chimera version | Ruby version |
20
+ |:----------------|:-------------|
21
+ | >= 1.1 | >= 2.5 |
22
+ | = 1.0 | >= 2.4 |
23
+ | <= 0.5 | >= 2.1 |
18
24
 
19
25
  ### ENV variables
20
26
 
@@ -81,6 +87,19 @@ The optional parameters are:
81
87
  * `user_agent` - if you would like your calls to identify with a specific user agent
82
88
  * `verbose` - the default is `false`, set it to true while debugging issues
83
89
  * `cache` - an instance of your cache solution, can be overwritten in any request
90
+ * `deserializers` - custom methods to deserialize the response body, below more details
91
+
92
+ ##### Custom deserializers
93
+
94
+ In case the API you are connecting to does not return JSON, you can pass custom deserializers to `Connection.new` or `Queue.new`:
95
+
96
+ deserializers: { error: your_error_deserializer, response: your_response_deserializer }
97
+
98
+ A Deserializer has to be an object on which the method `call` with the parameter `body` can be called:
99
+
100
+ custom_deserializer.call(body)
101
+
102
+ where `body` is the response body (in the default case a JSON object). The class `Deserializer` contains the default objects that are used. They might help you creating your own. Don't forget to make requests with another header than the default `"Content-Type" => "application/json"`, when the API you connect to does not support JSON.
84
103
 
85
104
  ### Request methods
86
105
 
@@ -263,10 +282,6 @@ Usually it does not have to be used directly. It is the class that executes the
263
282
 
264
283
  The `body` which it receives from the `Connection` class has to be in the in the (serialized) form in which the endpoint expects it. Usually this means you have to pass a JSON string to the `body` (it will **not** be serialized automatically).
265
284
 
266
- > Upcoming feature:
267
- >
268
- > It will be expanded by a `.queue` method, that will queue (sic) calls and run them in parallel and not run every call directly, like the `.run` method does.
269
-
270
285
  ## The Response class
271
286
 
272
287
  The `ChimeraHttpClient::Response` objects have the following interface:
@@ -276,9 +291,9 @@ The `ChimeraHttpClient::Response` objects have the following interface:
276
291
  * time (for monitoring)
277
292
  * response (the full response object, including the request)
278
293
  * error? (returns false)
279
- * parsed_body (returns the result of JSON.parse(body))
294
+ * parsed_body (returns the result of `deserializer[:response].call(body)`)
280
295
 
281
- If your API does not use JSON, but a different format e.g. XML, you can either monkey patch a `parsed_xml` method to the Response class, or let your wrapper handle the parsing of `body`.
296
+ If your API does not use JSON, but a different format e.g. XML, you can pass a custom deserializer to the Connection.
282
297
 
283
298
  ## Error classes
284
299
 
@@ -358,7 +373,7 @@ To inspect the requests waiting for execution, call `queue.queued_requests`.
358
373
 
359
374
  Add this line to your application's Gemfile:
360
375
 
361
- gem 'chimera_http_client', '~> 0.5'
376
+ gem 'chimera_http_client', '~> 1.1'
362
377
 
363
378
  And then execute:
364
379
 
data/TODO.markdown CHANGED
@@ -17,9 +17,9 @@ _none known_
17
17
 
18
18
  ### Custom De-serializer
19
19
 
20
- * [ ] allow to pass custom deserializer
21
- * [ ] use custom deserializer in #parsed_body instead of default JSON parsing
22
- * [ ] add example to README
20
+ * [x] ~~allow to pass custom deserializer~~
21
+ * [x] ~~use custom deserializer in #parsed_body instead of default JSON parsing~~
22
+ * [x] ~~add example to README~~
23
23
 
24
24
  ### Queueing / running in parallel
25
25
 
@@ -2,17 +2,18 @@ module ChimeraHttpClient
2
2
  class Base
3
3
  USER_AGENT = "ChimeraHttpClient (by mediafinger)".freeze
4
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?
5
+ def initialize(options = {})
6
+ fail(ChimeraHttpClient::ParameterMissingError, "base_url expected, but not given") if options[:base_url].nil?
7
7
 
8
- @base_url = base_url
9
- @logger = logger
10
- @timeout = timeout
8
+ @base_url = options.fetch(:base_url)
9
+ @deserializer = default_deserializer.merge(options.fetch(:deserializer, {}))
10
+ @logger = options[:logger]
11
+ @timeout = options[:timeout]
11
12
 
12
- Typhoeus::Config.cache = cache
13
+ Typhoeus::Config.cache = options[:cache]
13
14
  Typhoeus::Config.memoize = false # hydra setting, prevents a possible memory leak
14
- Typhoeus::Config.user_agent = user_agent
15
- Typhoeus::Config.verbose = verbose
15
+ Typhoeus::Config.user_agent = options.fetch(:user_agent, USER_AGENT)
16
+ Typhoeus::Config.verbose = options.fetch(:verbose, false)
16
17
  end
17
18
 
18
19
  private
@@ -42,6 +43,10 @@ module ChimeraHttpClient
42
43
  { "Content-Type" => "application/json" }
43
44
  end
44
45
 
46
+ def default_deserializer
47
+ { error: ::ChimeraHttpClient::Deserializer.json_error, response: ::ChimeraHttpClient::Deserializer.json_response }
48
+ end
49
+
45
50
  # Build URL out of @base_url and endpoint given as String or Array, while trimming redundant "/"
46
51
  def url(endpoint)
47
52
  trimmed_endpoint = Array(endpoint).map { |e| trim(e) }
@@ -11,7 +11,12 @@ module ChimeraHttpClient
11
11
  end
12
12
 
13
13
  def request
14
- @request ||= Request.new(logger: @logger)
14
+ options = {
15
+ logger: @logger,
16
+ deserializer: @deserializer,
17
+ }
18
+
19
+ @request ||= Request.new(options)
15
20
  end
16
21
 
17
22
  private
@@ -0,0 +1,31 @@
1
+ # This two JSON deserializers are the default ones
2
+ #
3
+ # To use custom deserializers, pass them as param to Connection.new or Queue.new:
4
+ # `deserializers: { error: your_error_deserializer, response: your_response_deserializer }`
5
+ # (you might be able to use the same for both cases)
6
+ #
7
+ # a Deserializer has to be an object on which the method `call` with the parameter `body` can be called:
8
+ # `custom_deserializer.call(body)`
9
+ # where `body` is the response body (in the default case a JSON object)
10
+ #
11
+ module ChimeraHttpClient
12
+ class Deserializer
13
+ class << self
14
+ def json_error
15
+ proc do |body|
16
+ JSON.parse(body)
17
+ rescue JSON::ParserError
18
+ { "non_json_body" => body }
19
+ end
20
+ end
21
+
22
+ def json_response
23
+ proc do |body|
24
+ JSON.parse(body)
25
+ rescue JSON::ParserError => e
26
+ raise ::ChimeraHttpClient::JsonParserError, "Could not parse body as JSON: #{body}, error: #{e.message}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,14 +1,15 @@
1
1
  module ChimeraHttpClient
2
2
  class Error < StandardError
3
- attr_reader :body, :code, :time, :response
3
+ attr_reader :body, :code, :time, :response, :deserializer
4
4
  alias message body
5
5
 
6
- def initialize(response)
6
+ def initialize(response, options = {})
7
7
  @body = response.body
8
8
  @code = response.code
9
9
  @time = response.options&.fetch(:total_time, nil)
10
10
  @response = response # contains the request
11
- super
11
+
12
+ @deserializer = options[:deserializer][:error]
12
13
  end
13
14
 
14
15
  def error?
@@ -16,9 +17,7 @@ module ChimeraHttpClient
16
17
  end
17
18
 
18
19
  def parsed_body
19
- JSON.parse(body)
20
- rescue JSON::ParserError
21
- { "non_json_body" => body }
20
+ deserializer.call(body)
22
21
  end
23
22
 
24
23
  def to_s
@@ -38,7 +38,12 @@ module ChimeraHttpClient
38
38
  private
39
39
 
40
40
  def create_request(method:, url:, body:, headers:, options:)
41
- Request.new(logger: @logger).create(
41
+ class_options = {
42
+ logger: @logger,
43
+ deserializer: @deserializer,
44
+ }
45
+
46
+ Request.new(class_options).create(
42
47
  method: method,
43
48
  url: url,
44
49
  body: body,
@@ -4,8 +4,9 @@ module ChimeraHttpClient
4
4
 
5
5
  attr_reader :request, :result
6
6
 
7
- def initialize(logger: nil)
8
- @logger = logger
7
+ def initialize(options = {})
8
+ @logger = options[:logger]
9
+ @options = options
9
10
  end
10
11
 
11
12
  def run(url:, method:, body: nil, options: {}, headers: {})
@@ -50,39 +51,39 @@ module ChimeraHttpClient
50
51
  private
51
52
 
52
53
  def on_complete_handler(response)
53
- return Response.new(response) if response.success?
54
+ return Response.new(response, @options) if response.success?
54
55
 
55
56
  exception_for(response)
56
57
  end
57
58
 
58
59
  def exception_for(response)
59
- return TimeoutError.new(response) if response.timed_out?
60
+ return TimeoutError.new(response, @options) if response.timed_out?
60
61
 
61
62
  case response.code.to_i
62
63
  when 301, 302, 303, 307
63
- RedirectionError.new(response)
64
+ RedirectionError.new(response, @options)
64
65
  when 200..399
65
66
  nil
66
67
  when 400
67
- BadRequestError.new(response)
68
+ BadRequestError.new(response, @options)
68
69
  when 401
69
- UnauthorizedError.new(response)
70
+ UnauthorizedError.new(response, @options)
70
71
  when 403
71
- ForbiddenError.new(response)
72
+ ForbiddenError.new(response, @options)
72
73
  when 404
73
- NotFoundError.new(response)
74
+ NotFoundError.new(response, @options)
74
75
  when 405
75
- MethodNotAllowedError.new(response)
76
+ MethodNotAllowedError.new(response, @options)
76
77
  when 409
77
- ResourceConflictError.new(response)
78
+ ResourceConflictError.new(response, @options)
78
79
  when 422
79
- UnprocessableEntityError.new(response)
80
+ UnprocessableEntityError.new(response, @options)
80
81
  when 400..499
81
- ClientError.new(response)
82
+ ClientError.new(response, @options)
82
83
  when 500..599
83
- ServerError.new(response)
84
+ ServerError.new(response, @options)
84
85
  else # response.code.zero?
85
- ConnectionError.new(response)
86
+ ConnectionError.new(response, @options)
86
87
  end
87
88
  end
88
89
  end
@@ -1,18 +1,18 @@
1
1
  module ChimeraHttpClient
2
2
  class Response
3
- attr_reader :body, :code, :time, :response
3
+ attr_reader :body, :code, :time, :response, :deserializer
4
4
 
5
- def initialize(response)
5
+ def initialize(response, options = {})
6
6
  @body = response.body
7
7
  @code = response.code
8
8
  @time = response.total_time
9
9
  @response = response # contains the request
10
+
11
+ @deserializer = options[:deserializer][:response]
10
12
  end
11
13
 
12
14
  def parsed_body
13
- JSON.parse(body)
14
- rescue JSON::ParserError => e
15
- raise ChimeraHttpClient::JsonParserError, "Could not parse body as JSON: #{body}, error: #{e.message}"
15
+ deserializer.call(body)
16
16
  end
17
17
 
18
18
  def error?
@@ -1,3 +1,3 @@
1
1
  module ChimeraHttpClient
2
- VERSION = "1.0.0".freeze
2
+ VERSION = "1.1.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: 1.0.0
4
+ version: 1.1.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-06-14 00:00:00.000000000 Z
11
+ date: 2019-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -171,6 +171,7 @@ files:
171
171
  - lib/chimera_http_client.rb
172
172
  - lib/chimera_http_client/base.rb
173
173
  - lib/chimera_http_client/connection.rb
174
+ - lib/chimera_http_client/deserializer.rb
174
175
  - lib/chimera_http_client/error.rb
175
176
  - lib/chimera_http_client/queue.rb
176
177
  - lib/chimera_http_client/request.rb