http-client-generator 0.2.3 → 0.2.4

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: 547094492a3531c3719f9d0aa0909b98d6f41f429da5670ec764cd73a507581d
4
- data.tar.gz: 64cb0d19b54b4f8d6b0acb4fc79d780810dc6abf42f94faa5541af5f586525b8
3
+ metadata.gz: dc140c4ff46aa9f676473ce9e79cd3391f52ba15fcc4e216c97ea60f19e87e16
4
+ data.tar.gz: f954c42beb245f685b796837484adab448f8ae980715b5f3dfea8160c5815277
5
5
  SHA512:
6
- metadata.gz: 9d0f5a805bc01653ad6d932d2e3df5988fdc7d2cad413ff9e4e35c0caf0c822fa9ffe94d5b7df15e4fe2d8d897a1d2304697160647e1905e459a36321bce2d3a
7
- data.tar.gz: 5105a5eb18be5e0cd16802ad99ded20b34951e76ac6b1d8dd71cfc8b5b9cfe40685a56e187d1e761899d7f728ddf17593561735bee5b7c9e09f87e973008536b
6
+ metadata.gz: d10565515b1a5123c7bf00a69322ff439a8a9091c916f41a8b1b2033912573130bffb9b6ff6485e1bfdc89a1c5f4b679a8da0583382a40c119fd5a205949802a
7
+ data.tar.gz: 816a1e79aa512d1772efd88c43a86167bf282c4be3c9e45b12ad507a5374aa9bc51bc2be7c6783ce1f6ce90b931cf9376ab8d7396ee37a621a1402fb21be9f52
data/README.md CHANGED
@@ -273,13 +273,19 @@ be called by the generated client methods.
273
273
  ## Plugs
274
274
 
275
275
  Plugs are objects that respond to `call(request)`. Request plugs run before the
276
- HTTP request. Response plugs run after the response body is read.
276
+ HTTP request. Response-head plugs run after the status is received but before
277
+ the body is read. Response plugs run after the response body is read.
277
278
 
278
279
  ```ruby
279
280
  resources do
280
281
  req_plug :set_request_id, :x_request_id
281
282
  req_plug :set_bearer_token, from_arg: :access_token
282
283
 
284
+ resp_head_plug ->(request) {
285
+ request.raise_message('Profile is unavailable') if request.response_status == 404
286
+ request
287
+ }
288
+
283
289
  resp_plug :enforce_json_response
284
290
  resp_plug :underscore_response
285
291
 
@@ -306,6 +312,30 @@ Built-in response plugs:
306
312
  | `:underscore_response` | Underscores parsed response keys. |
307
313
  | `:validate_response` | Validates parsed response bodies with a schema helper. |
308
314
 
315
+ `request.response_status` is the integer HTTP status code. It is available to
316
+ response-head plugs and ordinary response plugs.
317
+
318
+ ### Streaming responses
319
+
320
+ Declare `stream: true` to return the `HTTP::Response::Body` without eagerly
321
+ reading it. Consume the returned body with `each` or `readpartial`:
322
+
323
+ ```ruby
324
+ resources do
325
+ resp_head_plug ->(request) {
326
+ request.raise_message('Download failed') unless request.response_status == 200
327
+ request
328
+ }
329
+
330
+ get :download_archive, stream: true
331
+ end
332
+
333
+ Client.get_download_archive.each { |chunk| write_chunk(chunk) }
334
+ ```
335
+
336
+ Streaming resources cannot use ordinary `resp_plug`s because those plugs require
337
+ a materialized body. Use `resp_head_plug` for streaming-specific handling.
338
+
309
339
  Limit plugs to specific resources with `only:` or `except:`:
310
340
 
311
341
  ```ruby
@@ -16,7 +16,7 @@ module HttpClientGenerator
16
16
  end
17
17
 
18
18
  attr_accessor :verb, :name, :content_type, :timeout, :url, :headers, :body, :rest_args, :response_body,
19
- :base, :extra
19
+ :response_status, :base, :extra
20
20
 
21
21
  # rubocop:disable Metrics/ParameterLists
22
22
  def initialize(base:, name:, verb:, content_type:, timeout:, url:, body:, rest_args:)
@@ -4,24 +4,34 @@ require 'http'
4
4
 
5
5
  module HttpClientGenerator
6
6
  class Resource # :nodoc:
7
- attr_reader :verb, :content_type, :name, :req_plugs, :resp_plugs, :base, :timeout
7
+ attr_reader :verb, :content_type, :name, :req_plugs, :resp_head_plugs, :resp_plugs, :base, :timeout, :stream
8
8
 
9
9
  # rubocop:disable Metrics/ParameterLists
10
- def initialize(verb:, content_type:, timeout:, name:, base:, req_plugs:, resp_plugs:)
10
+ def initialize(verb:, content_type:, timeout:, name:, base:, req_plugs:, resp_head_plugs:, resp_plugs:,
11
+ stream: false)
11
12
  @verb = verb
12
13
  @base = base
13
14
  @content_type = content_type
14
15
  @timeout = timeout
15
16
  @name = name
17
+ @stream = stream
16
18
  @req_plugs = select_plugs(req_plugs)
19
+ @resp_head_plugs = select_plugs(resp_head_plugs)
17
20
  @resp_plugs = select_plugs(resp_plugs)
21
+ validate_streaming_plugs!
18
22
  end
19
23
  # rubocop:enable Metrics/ParameterLists
20
24
 
21
25
  def perform_request(url_helper, url_options, body, rest_args, timeout_override)
22
26
  request = prepare_request(url_helper, url_options, body, rest_args, timeout_override)
23
27
 
24
- request.response_body = perform_http_request(request).to_s
28
+ response = perform_http_request(request)
29
+ request.response_status = response.status.code
30
+ request = process_response_head(request)
31
+
32
+ return response.body if stream
33
+
34
+ request.response_body = response.to_s
25
35
 
26
36
  process_response(request)
27
37
  rescue HTTP::Error => e
@@ -69,6 +79,16 @@ module HttpClientGenerator
69
79
  request.response_body
70
80
  end
71
81
 
82
+ def process_response_head(request)
83
+ resp_head_plugs.reduce(request) { |req, plug| plug.call(req) }
84
+ end
85
+
86
+ def validate_streaming_plugs!
87
+ return unless stream && resp_plugs.any?
88
+
89
+ raise ArgumentError, "Streaming resource #{name.inspect} cannot use response body plugs"
90
+ end
91
+
72
92
  def select_plugs(plug_entries)
73
93
  plug_entries.filter_map do |entry|
74
94
  only = entry[:only]
@@ -10,11 +10,12 @@ module HttpClientGenerator
10
10
 
11
11
  HTTP_VERBS = %i[get post put patch].freeze
12
12
 
13
- def initialize(base, req_plugs = [], resp_plugs = [], timeout = nil)
13
+ def initialize(base, req_plugs = [], response_plugs = {}, timeout = nil)
14
14
  @base = base
15
15
  @resources = []
16
16
  @req_plugs = req_plugs
17
- @resp_plugs = resp_plugs
17
+ @resp_head_plugs = response_plugs.fetch(:head, [])
18
+ @resp_plugs = response_plugs.fetch(:body, [])
18
19
  @timeout = timeout
19
20
  end
20
21
 
@@ -32,12 +33,18 @@ module HttpClientGenerator
32
33
  @resp_plugs << build_plug_entry(plug, *args, only: only, except: except, **kwargs)
33
34
  end
34
35
 
36
+ def resp_head_plug(plug, *args, only: nil, except: nil, **kwargs)
37
+ @resp_head_plugs << build_plug_entry(plug, *args, only: only, except: except, **kwargs)
38
+ end
39
+
35
40
  def timeout(value = nil, **options)
36
41
  @timeout = TimeoutNormalizer.call(value, **options)
37
42
  end
38
43
 
39
44
  def namespace(_name = nil, &block)
40
- namespaced_definition = ResourcesDefinition.new(@base, @req_plugs.dup, @resp_plugs.dup, @timeout)
45
+ namespaced_definition = ResourcesDefinition.new(
46
+ @base, @req_plugs.dup, { head: @resp_head_plugs.dup, body: @resp_plugs.dup }, @timeout
47
+ )
41
48
  namespaced_definition.instance_eval(&block)
42
49
  @resources += namespaced_definition.resources
43
50
  end
@@ -70,6 +77,7 @@ module HttpClientGenerator
70
77
  name: name,
71
78
  base: @base,
72
79
  req_plugs: @req_plugs,
80
+ resp_head_plugs: @resp_head_plugs,
73
81
  resp_plugs: @resp_plugs,
74
82
  **resource_options
75
83
  )
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HttpClientGenerator
4
- VERSION = '0.2.3'
4
+ VERSION = '0.2.4'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http-client-generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Egorov