api_recipes 2.6.1 → 2.8.1

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: e8a4b8c1642a323a4a72f8303de3fbe408d15fab5a5f127fb5c2ad3fcb0f543a
4
- data.tar.gz: 2f24944c94c92e02224629c25a9c1da052c902d86abb8649d7faeb02e2111046
3
+ metadata.gz: c9d0a5a4530af3af22b9b22c091002d316e1bf7065c612d1d74f18f3aa62e37d
4
+ data.tar.gz: 5d322a843fa2db9cceb97cd9733b482ce17626342ad519ea036c0c821efe0d8b
5
5
  SHA512:
6
- metadata.gz: 445c2a2154979454088bb64e32c3e648d5cc779a184d6ae9079fed286913e66d7fec703d41d2de15f268aa386bc174230ce7ed2b5e5fa20a8bb2d9d8b16d92c0
7
- data.tar.gz: d22528bfcf3acbb9a0ebd8e3aa3826eb52985f3a081a1b71abcf29291d8958922c6a76be302b1fcad6fc45b1ca614008812050793ca19d6dec9400c73db390a9
6
+ metadata.gz: 6ee0d8d0c2e4c52aafa513c8619f92c1ec6b5425cf06911fc48d8d18562855cd4d0aabe96bf68985323663bdb4cb461e56b353c06431e2430a3ef9d51ecd6021
7
+ data.tar.gz: 4ef8593a855dd30fd21ee97642dcc5d832f7ec34218393131d1fe6758af1dbe4a8e5ad8d76f3612d289ef6e85d02a7640a65490f6b7dc103d0e32f43fbed2409
data/lib/api_recipes.rb CHANGED
@@ -32,13 +32,13 @@ module ApiRecipes
32
32
 
33
33
  define_method api_name do
34
34
  configs = ApiRecipes._aprcps_merge_apis_configs(api_name, configs.deep_symbolize_keys)
35
- api = Api.new(api_name, configs)
35
+ api = Api.new(api_name, configs, self)
36
36
  ApiRecipes.copy_global_authorizations_to_api api
37
37
  api
38
38
  end
39
39
  define_singleton_method api_name do
40
40
  configs = ApiRecipes._aprcps_merge_apis_configs(api_name, configs.deep_symbolize_keys)
41
- api = Api.new(api_name, configs)
41
+ api = Api.new(api_name, configs, self)
42
42
  ApiRecipes.copy_global_authorizations_to_api api
43
43
  api
44
44
  end
@@ -58,6 +58,7 @@ module ApiRecipes
58
58
  unless @configuration
59
59
  @configuration = Configuration.new
60
60
  end
61
+
61
62
  @configuration
62
63
  end
63
64
 
@@ -105,7 +106,7 @@ module ApiRecipes
105
106
  def self._aprcps_define_global_apis
106
107
  configuration.apis_configs.each do |api_name, api_configs|
107
108
  api_name = api_name.to_sym
108
- _aprcps_global_storage[api_name] = Api.new api_name, api_configs
109
+ _aprcps_global_storage[api_name] = Api.new api_name, api_configs, self
109
110
  define_singleton_method api_name do
110
111
  _aprcps_global_storage[api_name]
111
112
  end
@@ -116,6 +117,7 @@ module ApiRecipes
116
117
  unless @storage
117
118
  @storage = {}
118
119
  end
120
+
119
121
  @storage
120
122
  end
121
123
 
@@ -130,11 +132,9 @@ module ApiRecipes
130
132
  unless api_name.is_a?(String) || api_name.is_a?(Symbol)
131
133
  raise ArgumentError, "no api_name provided. Given: #{api_name.inspect}"
132
134
  end
133
- unless ApiRecipes.configuration.apis_configs[api_name]
134
- ApiRecipes.configuration.apis_configs[api_name] = {}
135
- end
135
+ global_api_configs = _aprcps_global_storage[api_name]&.configs || {}
136
136
  if configs
137
- ApiRecipes.configuration.apis_configs[api_name].merge(configs) do |_, old_val, new_val|
137
+ global_api_configs.deep_merge(configs) do |_, old_val, new_val|
138
138
  if new_val.nil?
139
139
  old_val
140
140
  else
@@ -142,7 +142,7 @@ module ApiRecipes
142
142
  end
143
143
  end
144
144
  else
145
- ApiRecipes.configuration.apis_configs[api_name]
145
+ global_api_configs
146
146
  end
147
147
  end
148
148
  end
@@ -2,13 +2,14 @@ module ApiRecipes
2
2
  class Api
3
3
 
4
4
  attr_accessor :name, :configs, :authorization, :basic_auth
5
- attr_reader :base_configs
5
+ attr_reader :base_configs, :object
6
6
 
7
- BASE_CONFIGS_KEYS = [:protocol, :host, :port, :api_version, :timeout, :on_bad_code]
7
+ BASE_CONFIGS_KEYS = [:protocol, :host, :port, :api_version, :timeout, :on_bad_code, :verify_with]
8
8
 
9
- def initialize(name, configs)
9
+ def initialize(name, configs, object)
10
10
  @name = name
11
11
  @configs = ApiRecipes::Settings::DEFAULT.merge configs
12
+ @object = object
12
13
 
13
14
  # Generate some_api.some_endpoint methods
14
15
  # e.g. github.users
@@ -3,6 +3,8 @@ module ApiRecipes
3
3
 
4
4
  attr_reader :api, :name, :params, :route, :children
5
5
 
6
+ FORWARDABLE_PARAMS = %i[verify_with].freeze
7
+
6
8
  def initialize(api: nil, name: nil, path: nil, params: {}, request_params: [], &block)
7
9
  @api = api
8
10
  @name = name
@@ -52,6 +54,8 @@ module ApiRecipes
52
54
  # puts "generating children of #{@name}: #{children.inspect}"
53
55
  if children
54
56
  children.each do |ep_name, pars|
57
+ pars = forwardable_params.merge(pars) if pars
58
+ # TODO: Merge pars with params
55
59
  # puts "Creating Endpoint '#{@name}' child '#{ep_name}' passing path #{build_path}"
56
60
  define_singleton_method ep_name do |*request_params, &block|
57
61
  Endpoint.new api: @api, name: ep_name, path: build_path, params: pars, request_params: request_params, &block
@@ -89,7 +93,6 @@ module ApiRecipes
89
93
  end
90
94
  # Merge DEFAULT_ROUTE_ATTRIBUTES with Api base_configs
91
95
  # Then merge the result with provided attributes
92
-
93
96
  @params = Settings::DEFAULT_ROUTE_ATTRIBUTES.inject({}) do |out, key_val|
94
97
  new_val = @api.base_configs[key_val.first]
95
98
  out[key_val.first] = new_val.nil? ? key_val.last : new_val
@@ -126,5 +129,9 @@ module ApiRecipes
126
129
  def required_params_for_path
127
130
  absolute_path.scan(/:(\w+)/).flatten.map { |p| p.to_sym }
128
131
  end
132
+
133
+ def forwardable_params
134
+ params.select { |k, v| FORWARDABLE_PARAMS.include? k }
135
+ end
129
136
  end
130
137
  end
@@ -40,8 +40,16 @@ module ApiRecipes
40
40
  end
41
41
 
42
42
  class ResponseCodeNotAsExpected < Exception
43
- def initialize(path, expected_code = nil, response_code = nil, response_body = nil)
44
- message = "response code for request on route '#{path}' has returned #{response_code}, but #{expected_code} was expected\n\nResponse body:\n #{response_body}"
43
+
44
+ attr_reader :path, :expected_code, :response
45
+
46
+ def initialize(path, expected_code = nil, response = nil, message: nil)
47
+ @path = path
48
+ @expected_code = expected_code
49
+ @response = response
50
+ unless message
51
+ message = "response code for request on route '#{@path}' has returned '#{@response.code}', but '#{@expected_code}' was expected\n\nResponse body:\n #{@response.body}"
52
+ end
45
53
  super(message)
46
54
  end
47
55
  end
@@ -11,6 +11,7 @@ module ApiRecipes
11
11
  def data
12
12
  return @data unless @data.nil?
13
13
 
14
+ # TODO: rescue nil?
14
15
  @data = @original_response.parse
15
16
  end
16
17
 
@@ -43,31 +43,40 @@ module ApiRecipes
43
43
 
44
44
  def build_url_from_path
45
45
  attrs = {
46
- scheme: settings[:protocol],
46
+ scheme: settings[:protocol].to_s,
47
47
  host: settings[:host],
48
48
  port: port,
49
- path: URI.escape(path)
49
+ path: path
50
50
  }
51
- URI::Generic.build attrs
51
+ URI::Generic.build2 attrs
52
52
  end
53
53
 
54
54
  def check_response_code
55
- # If :ok_code property is present, check the response code
56
55
  ok_code = false
57
56
  code = @response.code
58
- if expected_code = attributes[:ok_code]
59
- # If the code does not match, apply the requested strategy
60
- ok_code = true if code == expected_code
57
+ message = nil
58
+
59
+ verify_with = attributes[:verify_with]
60
+ if verify_with && @api.object.respond_to?(verify_with, true )
61
+ ok_code = @api.object.send verify_with, @response
62
+ message = "response for request on route '#{path}' was not valid. Verified with #{@api.object}##{verify_with}.\n\nResponse body:\n #{@response.body}"
61
63
  else
62
- # Default: 200 <= OK < 300
63
- ok_code = true if (code >= 200 && code < 300)
64
- expected_code = '200 <= CODE < 300'
64
+ # If :ok_code property is present, check the response code
65
+ if expected_code = attributes[:ok_code]
66
+ # If the code does not match, apply the requested strategy
67
+ ok_code = true if code == expected_code
68
+ else
69
+ # Default: 200 <= OK < 300
70
+ ok_code = true if @response.status.success?
71
+ expected_code = '200 <= CODE < 300'
72
+ end
65
73
  end
74
+
66
75
  unless ok_code
67
76
  case attributes[:on_bad_code].to_s
68
77
  when 'ignore'
69
78
  when 'raise'
70
- raise ResponseCodeNotAsExpected.new(path, expected_code, code, @response.body)
79
+ raise ResponseCodeNotAsExpected.new(path, expected_code, @response, message: message)
71
80
  end
72
81
  end
73
82
  end
@@ -81,12 +90,12 @@ module ApiRecipes
81
90
  end
82
91
 
83
92
  def port
84
- settings[:port] || case settings[:protocol]
85
- when 'http'
86
- 80
87
- when 'https'
88
- 443
89
- end
93
+ settings[:port].to_s || case settings[:protocol].to_s
94
+ when 'http'
95
+ '80'
96
+ when 'https'
97
+ '443'
98
+ end
90
99
  end
91
100
 
92
101
  def prepare_request
@@ -9,7 +9,8 @@ module ApiRecipes
9
9
  base_url: nil,
10
10
  timeout: 3,
11
11
  on_bad_code: 'raise',
12
- endpoints: {}
12
+ endpoints: {},
13
+ verify_with: nil
13
14
  }
14
15
 
15
16
  DEFAULT_ROUTE_ATTRIBUTES = {
@@ -18,7 +19,8 @@ module ApiRecipes
18
19
  path: nil,
19
20
  ok_code: nil,
20
21
  timeout: DEFAULT[:timeout],
21
- on_bad_code: DEFAULT[:on_bad_code]
22
+ on_bad_code: DEFAULT[:on_bad_code],
23
+ verify_with: DEFAULT[:verify_with]
22
24
  }
23
25
 
24
26
  AVAILABLE_PARAMS_ENCODINGS = %w(form params json body)
@@ -77,6 +77,37 @@ class Hash
77
77
  end
78
78
  end
79
79
 
80
+ # Returns a new hash with +self+ and +other_hash+ merged recursively.
81
+ #
82
+ # h1 = { a: true, b: { c: [1, 2, 3] } }
83
+ # h2 = { a: false, b: { x: [3, 4, 5] } }
84
+ #
85
+ # h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
86
+ #
87
+ # Like with Hash#merge in the standard library, a block can be provided
88
+ # to merge values:
89
+ #
90
+ # h1 = { a: 100, b: 200, c: { c1: 100 } }
91
+ # h2 = { b: 250, c: { c1: 200 } }
92
+ # h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
93
+ # # => { a: 100, b: 450, c: { c1: 300 } }
94
+ def deep_merge(other_hash, &block)
95
+ dup.deep_merge!(other_hash, &block)
96
+ end
97
+
98
+ # Same as +deep_merge+, but modifies +self+.
99
+ def deep_merge!(other_hash, &block)
100
+ merge!(other_hash) do |key, this_val, other_val|
101
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
102
+ this_val.deep_merge(other_val, &block)
103
+ elsif block_given?
104
+ block.call(key, this_val, other_val)
105
+ else
106
+ other_val
107
+ end
108
+ end
109
+ end
110
+
80
111
  # Returns a new hash with all keys converted by the block operation.
81
112
  # This includes the keys from the root hash and from all
82
113
  # nested hashes and arrays.
@@ -1,3 +1,3 @@
1
1
  module ApiRecipes
2
- VERSION = '2.6.1'.freeze
2
+ VERSION = '2.8.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_recipes
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.1
4
+ version: 2.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Verlato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-27 00:00:00.000000000 Z
11
+ date: 2021-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http