apimatic_core 0.1.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 +7 -0
- data/LICENSE +26 -0
- data/README.md +101 -0
- data/lib/apimatic-core/api_call.rb +103 -0
- data/lib/apimatic-core/authentication/header_auth.rb +21 -0
- data/lib/apimatic-core/authentication/multiple/and_auth_group.rb +28 -0
- data/lib/apimatic-core/authentication/multiple/auth_group.rb +45 -0
- data/lib/apimatic-core/authentication/multiple/or_auth_group.rb +29 -0
- data/lib/apimatic-core/authentication/multiple/single_auth.rb +48 -0
- data/lib/apimatic-core/authentication/query_auth.rb +21 -0
- data/lib/apimatic-core/configurations/global_configuration.rb +149 -0
- data/lib/apimatic-core/exceptions/invalid_auth_credential.rb +5 -0
- data/lib/apimatic-core/factories/http_response_factory.rb +14 -0
- data/lib/apimatic-core/http/configurations/http_client_configuration.rb +32 -0
- data/lib/apimatic-core/http/request/http_request.rb +50 -0
- data/lib/apimatic-core/http/response/api_response.rb +35 -0
- data/lib/apimatic-core/http/response/http_response.rb +24 -0
- data/lib/apimatic-core/logger/endpoint_logger.rb +28 -0
- data/lib/apimatic-core/request_builder.rb +361 -0
- data/lib/apimatic-core/response_handler.rb +269 -0
- data/lib/apimatic-core/types/error_case.rb +37 -0
- data/lib/apimatic-core/types/parameter.rb +116 -0
- data/lib/apimatic-core/types/sdk/api_exception.rb +15 -0
- data/lib/apimatic-core/types/sdk/base_model.rb +22 -0
- data/lib/apimatic-core/types/sdk/file_wrapper.rb +11 -0
- data/lib/apimatic-core/types/sdk/validation_exception.rb +10 -0
- data/lib/apimatic-core/types/xml_attributes.rb +37 -0
- data/lib/apimatic-core/utilities/api_helper.rb +551 -0
- data/lib/apimatic-core/utilities/auth_helper.rb +49 -0
- data/lib/apimatic-core/utilities/comparison_helper.rb +77 -0
- data/lib/apimatic-core/utilities/date_time_helper.rb +126 -0
- data/lib/apimatic-core/utilities/file_helper.rb +21 -0
- data/lib/apimatic-core/utilities/xml_helper.rb +215 -0
- data/lib/apimatic_core.rb +44 -0
- metadata +215 -0
@@ -0,0 +1,551 @@
|
|
1
|
+
require 'erb'
|
2
|
+
module CoreLibrary
|
3
|
+
# API utility class involved in executing an API
|
4
|
+
class ApiHelper
|
5
|
+
# Serializes an array parameter (creates key value pairs).
|
6
|
+
# @param [String] key The name of the parameter.
|
7
|
+
# @param [Array] array The value of the parameter.
|
8
|
+
# @param [String] formatting The format of the serialization.
|
9
|
+
def self.serialize_array(key, array, formatting: 'indexed')
|
10
|
+
tuples = []
|
11
|
+
|
12
|
+
tuples += case formatting
|
13
|
+
when 'csv'
|
14
|
+
[[key, array.map { |element| CGI.escape(element.to_s) }.join(',')]]
|
15
|
+
when 'psv'
|
16
|
+
[[key, array.map { |element| CGI.escape(element.to_s) }.join('|')]]
|
17
|
+
when 'tsv'
|
18
|
+
[[key, array.map { |element| CGI.escape(element.to_s) }.join("\t")]]
|
19
|
+
else
|
20
|
+
array.map { |element| [key, element] }
|
21
|
+
end
|
22
|
+
tuples
|
23
|
+
end
|
24
|
+
|
25
|
+
# Deserializes primitive types like Boolean, String etc.
|
26
|
+
# @param response The response received.
|
27
|
+
# @param type Type to be deserialized.
|
28
|
+
# @param is_array Is the response provided an array or not
|
29
|
+
def self.deserialize_primitive_types(response, type, is_array, should_symbolize)
|
30
|
+
return json_deserialize(response, should_symbolize) if is_array
|
31
|
+
raise ArgumentError, 'callable has not been not provided for deserializer.' if type.nil?
|
32
|
+
|
33
|
+
type.call(response)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Deserializes datetime.
|
37
|
+
# @param response The response received.
|
38
|
+
# @param datetime_format Current format of datetime.
|
39
|
+
# @param is_array Is the response provided an array or not
|
40
|
+
def self.deserialize_datetime(response, datetime_format, is_array, should_symbolize)
|
41
|
+
decoded = json_deserialize(response, should_symbolize) if is_array
|
42
|
+
|
43
|
+
case datetime_format
|
44
|
+
when DateTimeFormat::HTTP_DATE_TIME
|
45
|
+
return DateTimeHelper.from_rfc1123(response) unless is_array
|
46
|
+
|
47
|
+
decoded.map { |element| DateTimeHelper.from_rfc1123(element) }
|
48
|
+
when DateTimeFormat::RFC3339_DATE_TIME
|
49
|
+
return DateTimeHelper.from_rfc3339(response) unless is_array
|
50
|
+
|
51
|
+
decoded.map { |element| DateTimeHelper.from_rfc3339(element) }
|
52
|
+
when DateTimeFormat::UNIX_DATE_TIME
|
53
|
+
return DateTimeHelper.from_unix(response) unless is_array
|
54
|
+
|
55
|
+
decoded.map { |element| DateTimeHelper.from_unix(element) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Deserializes date.
|
60
|
+
# @param response The response received.
|
61
|
+
# @param is_array Is the response provided an array or not
|
62
|
+
def self.date_deserializer(response, is_array, should_symbolize)
|
63
|
+
if is_array
|
64
|
+
decoded = json_deserialize(response, should_symbolize)
|
65
|
+
return decoded.map { |element| Date.iso8601(element) }
|
66
|
+
end
|
67
|
+
Date.iso8601(response)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Deserializer to use when the type of response is not known beforehand.
|
71
|
+
# @param response The response received.
|
72
|
+
def self.dynamic_deserializer(response, should_symbolize)
|
73
|
+
decoded = json_deserialize(response, should_symbolize) unless response.nil? ||
|
74
|
+
response.to_s.strip.empty?
|
75
|
+
decoded
|
76
|
+
end
|
77
|
+
|
78
|
+
# Deserializes response to a known custom model type.
|
79
|
+
# @param response The response received.
|
80
|
+
# @param deserialize_into The custom model type to deserialize into.
|
81
|
+
# @param is_array Is the response provided an array or not
|
82
|
+
def self.custom_type_deserializer(response, deserialize_into, is_array, should_symbolize)
|
83
|
+
decoded = json_deserialize(response, should_symbolize)
|
84
|
+
return deserialize_into.call(decoded) unless is_array
|
85
|
+
|
86
|
+
decoded.map { |element| deserialize_into.call(element) }
|
87
|
+
end
|
88
|
+
|
89
|
+
# Replaces template parameters in the given url.
|
90
|
+
# @param [String] query_builder The query string builder to replace the template
|
91
|
+
# parameters.
|
92
|
+
# @param [Hash] parameters The parameters to replace in the url.
|
93
|
+
def self.append_url_with_template_parameters(query_builder, parameters)
|
94
|
+
# perform parameter validation
|
95
|
+
unless query_builder.instance_of? String
|
96
|
+
raise ArgumentError, 'Given value for parameter \"query_builder\" is
|
97
|
+
invalid.'
|
98
|
+
end
|
99
|
+
|
100
|
+
# Return if there are no parameters to replace.
|
101
|
+
return query_builder if parameters.nil?
|
102
|
+
|
103
|
+
parameters.each do |key, val|
|
104
|
+
if val.nil?
|
105
|
+
replace_value = ''
|
106
|
+
elsif val['value'].instance_of? Array
|
107
|
+
if val['encode'] == true
|
108
|
+
val['value'].map! { |element| CGI.escape(element.to_s) }
|
109
|
+
else
|
110
|
+
val['value'].map!(&:to_s)
|
111
|
+
end
|
112
|
+
replace_value = val['value'].join('/')
|
113
|
+
else
|
114
|
+
replace_value = if val['encode'] == true
|
115
|
+
CGI.escape(val['value'].to_s)
|
116
|
+
else
|
117
|
+
val['value'].to_s
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Find the template parameter and replace it with its value.
|
122
|
+
query_builder = query_builder.gsub("{#{key}}", replace_value)
|
123
|
+
end
|
124
|
+
query_builder
|
125
|
+
end
|
126
|
+
|
127
|
+
# Replaces the template parameters in the given user-agent string.
|
128
|
+
# @param [String] user_agent The user_agent value to be replaced with the given
|
129
|
+
# parameters.
|
130
|
+
# @param [Hash] parameters The parameters to replace in the user_agent.
|
131
|
+
def self.update_user_agent_value_with_parameters(user_agent, parameters)
|
132
|
+
# perform parameter validation
|
133
|
+
unless user_agent.instance_of? String
|
134
|
+
raise ArgumentError, 'Given value for \"user_agent\" is
|
135
|
+
invalid.'
|
136
|
+
end
|
137
|
+
|
138
|
+
# Return if there are no parameters to replace.
|
139
|
+
return user_agent if parameters.nil?
|
140
|
+
|
141
|
+
parameters.each do |key, val|
|
142
|
+
if val.nil?
|
143
|
+
replace_value = ''
|
144
|
+
elsif val['value'].instance_of? Array
|
145
|
+
if val['encode'] == true
|
146
|
+
val['value'].map! { |element| ERB::Util.url_encode(element.to_s) }
|
147
|
+
else
|
148
|
+
val['value'].map!(&:to_s)
|
149
|
+
end
|
150
|
+
replace_value = val['value'].join('/')
|
151
|
+
else
|
152
|
+
replace_value = if val['encode'] == true
|
153
|
+
ERB::Util.url_encode(val['value'].to_s)
|
154
|
+
else
|
155
|
+
val['value'].to_s
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Find the template parameter and replace it with its value.
|
160
|
+
user_agent = user_agent.gsub(key.to_s, replace_value)
|
161
|
+
end
|
162
|
+
user_agent
|
163
|
+
end
|
164
|
+
|
165
|
+
# Appends the given set of parameters to the given query string.
|
166
|
+
# @param [String] query_builder The query string builder to add the query parameters to.
|
167
|
+
# @param [Hash] parameters The parameters to append.
|
168
|
+
# @param [String] array_serialization The serialization format
|
169
|
+
def self.append_url_with_query_parameters(query_builder, parameters,
|
170
|
+
array_serialization = ArraySerializationFormat::INDEXED)
|
171
|
+
# Perform parameter validation.
|
172
|
+
unless query_builder.instance_of? String
|
173
|
+
raise ArgumentError, 'Given value for parameter \"query_builder\"
|
174
|
+
is invalid.'
|
175
|
+
end
|
176
|
+
|
177
|
+
# Return if there are no parameters to replace.
|
178
|
+
return query_builder if parameters.nil?
|
179
|
+
|
180
|
+
parameters = process_complex_types_parameters(parameters, array_serialization)
|
181
|
+
|
182
|
+
parameters.each do |key, value|
|
183
|
+
seperator = query_builder.include?('?') ? '&' : '?'
|
184
|
+
unless value.nil?
|
185
|
+
if value.instance_of? Array
|
186
|
+
value.compact!
|
187
|
+
serialize_array(
|
188
|
+
key, value, formatting: array_serialization
|
189
|
+
).each do |element|
|
190
|
+
seperator = query_builder.include?('?') ? '&' : '?'
|
191
|
+
query_builder += "#{seperator}#{element[0]}=#{element[1]}"
|
192
|
+
end
|
193
|
+
else
|
194
|
+
query_builder += "#{seperator}#{key}=#{CGI.escape(value.to_s)}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
query_builder
|
199
|
+
end
|
200
|
+
|
201
|
+
# Validates and processes the given Url.
|
202
|
+
# @param [String] url The given Url to process.
|
203
|
+
# @return [String] Pre-processed Url as string.
|
204
|
+
def self.clean_url(url)
|
205
|
+
# Perform parameter validation.
|
206
|
+
raise ArgumentError, 'Invalid Url.' unless url.instance_of? String
|
207
|
+
|
208
|
+
# Ensure that the urls are absolute.
|
209
|
+
matches = url.match(%r{^(https?://[^/]+)})
|
210
|
+
raise ArgumentError, 'Invalid Url format.' if matches.nil?
|
211
|
+
|
212
|
+
# Get the http protocol match.
|
213
|
+
protocol = matches[1]
|
214
|
+
|
215
|
+
# Check if parameters exist.
|
216
|
+
index = url.index('?')
|
217
|
+
|
218
|
+
# Remove redundant forward slashes.
|
219
|
+
query = url[protocol.length...(!index.nil? ? index : url.length)]
|
220
|
+
query.gsub!(%r{//+}, '/')
|
221
|
+
|
222
|
+
# Get the parameters.
|
223
|
+
parameters = !index.nil? ? url[url.index('?')...url.length] : ''
|
224
|
+
|
225
|
+
# Return processed url.
|
226
|
+
protocol + query + parameters
|
227
|
+
end
|
228
|
+
|
229
|
+
# Parses JSON string.
|
230
|
+
# @param [String] json A JSON string.
|
231
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
232
|
+
def self.json_deserialize(json, should_symbolize = false)
|
233
|
+
JSON.parse(json, symbolize_names: should_symbolize)
|
234
|
+
rescue StandardError
|
235
|
+
raise TypeError, 'Server responded with invalid JSON.'
|
236
|
+
end
|
237
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
238
|
+
|
239
|
+
# Parses JSON string.
|
240
|
+
# @param [object] obj The object to serialize.
|
241
|
+
def self.json_serialize(obj)
|
242
|
+
serializable_types.map { |x| obj.is_a? x }.any? ? obj.to_s : obj.to_json
|
243
|
+
end
|
244
|
+
|
245
|
+
# Removes elements with empty values from a hash.
|
246
|
+
# @param [Hash] hash The hash to clean.
|
247
|
+
def self.clean_hash(hash)
|
248
|
+
hash.delete_if { |_key, value| value.to_s.strip.empty? }
|
249
|
+
end
|
250
|
+
|
251
|
+
# Form encodes a hash of parameters.
|
252
|
+
# @param [Hash] form_parameters The hash of parameters to encode.
|
253
|
+
# @return [Hash] A hash with the same parameters form encoded.
|
254
|
+
def self.form_encode_parameters(form_parameters, array_serialization)
|
255
|
+
encoded = {}
|
256
|
+
form_parameters.each do |key, value|
|
257
|
+
encoded.merge!(form_encode(value, key, formatting:
|
258
|
+
array_serialization))
|
259
|
+
end
|
260
|
+
encoded
|
261
|
+
end
|
262
|
+
|
263
|
+
# Process complex types in query_params.
|
264
|
+
# @param [Hash] query_parameters The hash of query parameters.
|
265
|
+
# @return [Hash] array_serialization A hash with the processed query parameters.
|
266
|
+
def self.process_complex_types_parameters(query_parameters, array_serialization)
|
267
|
+
processed_params = {}
|
268
|
+
query_parameters.each do |key, value|
|
269
|
+
processed_params.merge!(ApiHelper.form_encode(value, key, formatting:
|
270
|
+
array_serialization))
|
271
|
+
end
|
272
|
+
processed_params
|
273
|
+
end
|
274
|
+
|
275
|
+
def self.custom_merge(a, b)
|
276
|
+
x = {}
|
277
|
+
a.each do |key, value_a|
|
278
|
+
b.each do |k, value_b|
|
279
|
+
next unless key == k
|
280
|
+
|
281
|
+
x[k] = []
|
282
|
+
if value_a.instance_of? Array
|
283
|
+
value_a.each do |v|
|
284
|
+
x[k].push(v)
|
285
|
+
end
|
286
|
+
else
|
287
|
+
x[k].push(value_a)
|
288
|
+
end
|
289
|
+
if value_b.instance_of? Array
|
290
|
+
value_b.each do |v|
|
291
|
+
x[k].push(v)
|
292
|
+
end
|
293
|
+
else
|
294
|
+
x[k].push(value_b)
|
295
|
+
end
|
296
|
+
a.delete(k)
|
297
|
+
b.delete(k)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
x.merge!(a)
|
301
|
+
x.merge!(b)
|
302
|
+
x
|
303
|
+
end
|
304
|
+
|
305
|
+
# Form encodes an object.
|
306
|
+
# @param [Dynamic] obj An object to form encode.
|
307
|
+
# @param [String] instance_name The name of the object.
|
308
|
+
# @return [Hash] A form encoded representation of the object in the form
|
309
|
+
# of a hash.
|
310
|
+
def self.form_encode(obj, instance_name, formatting: ArraySerializationFormat::INDEXED)
|
311
|
+
retval = {}
|
312
|
+
|
313
|
+
# If this is a structure, resolve it's field names.
|
314
|
+
obj = obj.to_hash if obj.is_a? BaseModel
|
315
|
+
|
316
|
+
# Create a form encoded hash for this object.
|
317
|
+
if obj.nil?
|
318
|
+
nil
|
319
|
+
elsif obj.instance_of? Array
|
320
|
+
if formatting == ArraySerializationFormat::INDEXED
|
321
|
+
obj.each_with_index do |value, index|
|
322
|
+
retval.merge!(form_encode(value, "#{instance_name}[#{index}]"))
|
323
|
+
end
|
324
|
+
elsif serializable_types.map { |x| obj[0].is_a? x }.any?
|
325
|
+
obj.each do |value|
|
326
|
+
abc = if formatting == ArraySerializationFormat::UN_INDEXED
|
327
|
+
form_encode(value, "#{instance_name}[]",
|
328
|
+
formatting: formatting)
|
329
|
+
else
|
330
|
+
form_encode(value, instance_name,
|
331
|
+
formatting: formatting)
|
332
|
+
end
|
333
|
+
retval = custom_merge(retval, abc)
|
334
|
+
end
|
335
|
+
else
|
336
|
+
obj.each_with_index do |value, index|
|
337
|
+
retval.merge!(form_encode(value, "#{instance_name}[#{index}]",
|
338
|
+
formatting: formatting))
|
339
|
+
end
|
340
|
+
end
|
341
|
+
elsif obj.instance_of? Hash
|
342
|
+
obj.each do |key, value|
|
343
|
+
retval.merge!(form_encode(value, "#{instance_name}[#{key}]",
|
344
|
+
formatting: formatting))
|
345
|
+
end
|
346
|
+
elsif obj.instance_of? File
|
347
|
+
retval[instance_name] = UploadIO.new(
|
348
|
+
obj, 'application/octet-stream', File.basename(obj.path)
|
349
|
+
)
|
350
|
+
else
|
351
|
+
retval[instance_name] = obj
|
352
|
+
end
|
353
|
+
retval
|
354
|
+
end
|
355
|
+
|
356
|
+
# Retrieves a field from a Hash/Array based on an Array of keys/indexes
|
357
|
+
# @param [Hash, Array] obj The hash to extract data from
|
358
|
+
# @param [Array<String, Integer>] keys The keys/indexes to use
|
359
|
+
# @return [Object] The extracted value
|
360
|
+
def self.map_response(obj, keys)
|
361
|
+
val = obj
|
362
|
+
begin
|
363
|
+
keys.each do |key|
|
364
|
+
val = if val.is_a? Array
|
365
|
+
if key.to_i.to_s == key
|
366
|
+
val[key.to_i]
|
367
|
+
else
|
368
|
+
val = nil
|
369
|
+
end
|
370
|
+
else
|
371
|
+
val.fetch(key.to_sym)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
rescue NoMethodError, TypeError, IndexError
|
375
|
+
val = nil
|
376
|
+
end
|
377
|
+
val
|
378
|
+
end
|
379
|
+
|
380
|
+
# Deserialize the value against the template (group of types).
|
381
|
+
# @param [String] value The value to be deserialized.
|
382
|
+
# @param [String] template The type-combination group for which the value will be mapped (oneOf(Integer, String)).
|
383
|
+
def self.deserialize(template, value, sdk_module, should_symbolize)
|
384
|
+
decoded = json_deserialize(value, should_symbolize)
|
385
|
+
map_types(decoded, template, sdk_module: sdk_module)
|
386
|
+
end
|
387
|
+
|
388
|
+
# Validates and processes the value against the template(group of types).
|
389
|
+
# @param [String] value The value to be mapped against the template.
|
390
|
+
# @param [String] template The parameter indicates the group of types (oneOf(Integer, String)).
|
391
|
+
# @param [String] group_name The parameter indicates the group (oneOf|anyOf).
|
392
|
+
def self.map_types(value, template, group_name: nil, sdk_module: nil)
|
393
|
+
result_value = nil
|
394
|
+
matches = 0
|
395
|
+
types = []
|
396
|
+
group_name = template.partition('(').first if group_name.nil? && template.match?(/anyOf|oneOf/)
|
397
|
+
|
398
|
+
return if value.nil?
|
399
|
+
|
400
|
+
if template.end_with?('{}') || template.end_with?('[]')
|
401
|
+
types = template.split(group_name, 2).last.gsub(/\s+/, '').split
|
402
|
+
else
|
403
|
+
template = template.split(group_name, 2).last.delete_prefix('(').delete_suffix(')')
|
404
|
+
types = template.scan(/(anyOf|oneOf)[(]([^[)]]*)[)]/).flatten.combination(2).map { |a, b| "#{a}(#{b})" }
|
405
|
+
types.each { |t| template = template.gsub(", #{t}", '') }
|
406
|
+
types = template.gsub(/\s+/, '').split(',').push(*types)
|
407
|
+
end
|
408
|
+
types.each do |element|
|
409
|
+
if element.match?(/^(oneOf|anyOf)[(].*$/)
|
410
|
+
begin
|
411
|
+
result_value = map_types(value, element, matches)
|
412
|
+
matches += 1
|
413
|
+
rescue ValidationException
|
414
|
+
next
|
415
|
+
end
|
416
|
+
elsif element.end_with?('{}')
|
417
|
+
result_value, matches = map_hash_type(value, element, group_name, matches)
|
418
|
+
elsif element.end_with?('[]')
|
419
|
+
result_value, matches = map_array_type(value, element, group_name, matches)
|
420
|
+
else
|
421
|
+
begin
|
422
|
+
result_value, matches = map_type(value, element, group_name, matches, sdk_module)
|
423
|
+
rescue StandardError
|
424
|
+
next
|
425
|
+
end
|
426
|
+
end
|
427
|
+
break if group_name == 'anyOf' && matches == 1
|
428
|
+
end
|
429
|
+
raise ValidationException, "The value #{value} provided doesn't validate against the schema #{template}" unless
|
430
|
+
matches == 1
|
431
|
+
|
432
|
+
value = result_value unless result_value.nil?
|
433
|
+
value
|
434
|
+
end
|
435
|
+
|
436
|
+
# Validates and processes the value against the [Hash] type.
|
437
|
+
# @param [String] value The value to be mapped against the type.
|
438
|
+
# @param [String] type The possible type of the value.
|
439
|
+
# @param [String] group_name The parameter indicates the group (oneOf|anyOf).
|
440
|
+
# @param [Integer] matches The parameter indicates the number of matches of value against types.
|
441
|
+
def self.map_hash_type(value, type, group_name, matches)
|
442
|
+
if value.instance_of? Hash
|
443
|
+
decoded = {}
|
444
|
+
value.each do |key, val|
|
445
|
+
type = type.chomp('{}').to_s
|
446
|
+
val = map_types(val, type, group_name: group_name)
|
447
|
+
decoded[key] = val unless type.empty?
|
448
|
+
rescue ValidationException
|
449
|
+
next
|
450
|
+
end
|
451
|
+
matches += 1 if decoded.length == value.length
|
452
|
+
value = decoded unless decoded.empty?
|
453
|
+
end
|
454
|
+
[value, matches]
|
455
|
+
end
|
456
|
+
|
457
|
+
# Validates and processes the value against the [Array] type.
|
458
|
+
# @param [String] value The value to be mapped against the type.
|
459
|
+
# @param [String] type The possible type of the value.
|
460
|
+
# @param [String] group_name The parameter indicates the group (oneOf|anyOf).
|
461
|
+
# @param [Integer] matches The parameter indicates the number of matches of value against types.
|
462
|
+
def self.map_array_type(value, type, group_name, matches)
|
463
|
+
if value.instance_of? Array
|
464
|
+
decoded = []
|
465
|
+
value.each do |val|
|
466
|
+
type = type.chomp('[]').to_s
|
467
|
+
val = map_types(val, type, group_name: group_name)
|
468
|
+
decoded.append(val) unless type.empty?
|
469
|
+
rescue ValidationException
|
470
|
+
next
|
471
|
+
end
|
472
|
+
matches += 1 if decoded.length == value.length
|
473
|
+
value = decoded unless decoded.empty?
|
474
|
+
end
|
475
|
+
[value, matches]
|
476
|
+
end
|
477
|
+
|
478
|
+
# Validates and processes the value against the type.
|
479
|
+
# @param [String] value The value to be mapped against the type.
|
480
|
+
# @param [String] type The possible type of the value.
|
481
|
+
# @param [String] _group_name The parameter indicates the group (oneOf|anyOf).
|
482
|
+
# @param [Integer] matches The parameter indicates the number of matches of value against types.
|
483
|
+
def self.map_type(value, type, _group_name, matches, sdk_module)
|
484
|
+
if sdk_module.constants.select do |c|
|
485
|
+
sdk_module.const_get(c).to_s == "#{sdk_module}::#{type}"
|
486
|
+
end.empty?
|
487
|
+
value, matches = map_data_type(value, type, matches)
|
488
|
+
else
|
489
|
+
value, matches = map_complex_type(value, type, matches, sdk_module)
|
490
|
+
end
|
491
|
+
[value, matches]
|
492
|
+
end
|
493
|
+
|
494
|
+
# Validates and processes the value against the complex types.
|
495
|
+
# @param [String] value The value to be mapped against the type.
|
496
|
+
# @param [String] type The possible type of the value.
|
497
|
+
# @param [Integer] matches The parameter indicates the number of matches of value against types.
|
498
|
+
def self.map_complex_type(value, type, matches, sdk_module)
|
499
|
+
# TODO: Add a nil check on sdk_module?
|
500
|
+
obj = sdk_module.const_get(type)
|
501
|
+
value = if obj.respond_to? 'from_hash'
|
502
|
+
obj.send('from_hash', value)
|
503
|
+
else
|
504
|
+
obj.constants.find { |k| obj.const_get(k) == value }
|
505
|
+
end
|
506
|
+
matches += 1 unless value.nil?
|
507
|
+
[value, matches]
|
508
|
+
end
|
509
|
+
|
510
|
+
# Validates and processes the value against the data types.
|
511
|
+
# @param [String] value The value to be mapped against the type.
|
512
|
+
# @param [String] element The possible type of the value.
|
513
|
+
# @param [Integer] matches The parameter indicates the number of matches of value against types.
|
514
|
+
def self.map_data_type(value, element, matches)
|
515
|
+
element = element.split('|').map { |x| Object.const_get x }
|
516
|
+
matches += 1 if element.all? { |x| data_types.include?(x) } &&
|
517
|
+
element.any? { |x| (value.instance_of? x) || (value.class.ancestors.include? x) }
|
518
|
+
[value, matches]
|
519
|
+
end
|
520
|
+
|
521
|
+
# Validates the value against the template(group of types).
|
522
|
+
# @param [String] value The value to be mapped against the type.
|
523
|
+
# @param [String] template The parameter indicates the group of types (oneOf(Integer, String)).
|
524
|
+
def self.validate_types(value, template, sdk_module, should_symbolize)
|
525
|
+
map_types(json_deserialize(value.to_json, should_symbolize), template, sdk_module: sdk_module)
|
526
|
+
end
|
527
|
+
|
528
|
+
# Get content-type depending on the value
|
529
|
+
# @param [Object] value The value for which the content-type is resolved.
|
530
|
+
def self.get_content_type(value)
|
531
|
+
if serializable_types.map { |x| value.is_a? x }.any?
|
532
|
+
'text/plain; charset=utf-8'
|
533
|
+
else
|
534
|
+
'application/json; charset=utf-8'
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
# Array of serializable types
|
539
|
+
def self.serializable_types
|
540
|
+
[String, Numeric, TrueClass,
|
541
|
+
FalseClass, Date, DateTime]
|
542
|
+
end
|
543
|
+
|
544
|
+
# Array of supported data types
|
545
|
+
def self.data_types
|
546
|
+
[String, Float, Integer,
|
547
|
+
TrueClass, FalseClass, Date,
|
548
|
+
DateTime, Array, Hash, Object]
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module CoreLibrary
|
4
|
+
# A utility class for authentication flow
|
5
|
+
class AuthHelper
|
6
|
+
# Performs the Base64 encodes the provided parameters after joining the parameters with delimiter.
|
7
|
+
# @param [String] *props The string properties which should participate in encoding.
|
8
|
+
# @param [String|Optional] delimiter The delimiter to use while joining the properties.
|
9
|
+
# @return [String] The encoded Base64 string.
|
10
|
+
def self.get_base64_encoded_value(*props, delimiter: ':')
|
11
|
+
return if props.any?(&:nil?)
|
12
|
+
|
13
|
+
joined = props.join(delimiter)
|
14
|
+
Base64.strict_encode64(joined)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Checks if OAuth token has expired.
|
18
|
+
# @param [int] token_expiry The expiring of a token.
|
19
|
+
# @return [Boolean] true if token has expired, false otherwise.
|
20
|
+
def self.token_expired?(token_expiry)
|
21
|
+
raise ArgumentError, 'Token expiry can not be nil.' if token_expiry.nil?
|
22
|
+
|
23
|
+
token_expiry < Time.now.utc.to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
# Calculates the expiry after adding the expires_in value to the current timestamp.
|
27
|
+
# @param [int] expires_in The number of ticks after which the token would get expired.
|
28
|
+
# @param [int] current_timestamp The current timestamp.
|
29
|
+
# @return [Time] The calculated expiry time of the token.
|
30
|
+
def self.get_token_expiry(expires_in, current_timestamp)
|
31
|
+
current_timestamp + expires_in
|
32
|
+
end
|
33
|
+
|
34
|
+
# Checks whether the provided auth parameters does not contain any nil key/value.
|
35
|
+
# @param [Hash] auth_params The auth parameters hash to check against.
|
36
|
+
# @return [Boolean] True if there is not any nil key/value in the given auth parameters.
|
37
|
+
def self.valid_auth?(auth_params)
|
38
|
+
!auth_params.nil? and !auth_params.empty? and
|
39
|
+
auth_params.all? { |key, value| !(key.nil? or value.nil?) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Applies callable to each entry of the hash.
|
43
|
+
# @param [Hash] auth_params The auth parameters hash to apply against.
|
44
|
+
# @param [Callable] func The callable function to apply for each entry of the provided hash.
|
45
|
+
def self.apply(auth_params, func)
|
46
|
+
auth_params.each { |key, value| func.call(key, value) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module CoreLibrary
|
2
|
+
# A utility that perform the comparison of the Response body and headers.
|
3
|
+
class ComparisonHelper
|
4
|
+
|
5
|
+
# Class method to compare the received headers with the expected headers.
|
6
|
+
# @param [Hash] expected_headers A hash of expected headers (keys in lower case).
|
7
|
+
# @param [Hash] actual_headers A hash of actual headers.
|
8
|
+
# @param [Boolean, optional] allow_extra A flag which determines if we allow extra headers.
|
9
|
+
def self.match_headers(expected_headers,
|
10
|
+
actual_headers,
|
11
|
+
allow_extra: true)
|
12
|
+
return false if ((actual_headers.length < expected_headers.length) ||
|
13
|
+
((allow_extra == false) && (actual_headers.length > expected_headers.length)))
|
14
|
+
|
15
|
+
actual_headers = Hash[actual_headers.map{|k, v| [k.to_s.downcase, v]}]
|
16
|
+
expected_headers = Hash[expected_headers.map{|k, v| [k.to_s.downcase, v]}]
|
17
|
+
|
18
|
+
expected_headers.each do |e_key, e_value|
|
19
|
+
return false unless actual_headers.key?(e_key)
|
20
|
+
return false if ((e_value != nil) &&
|
21
|
+
(e_value != actual_headers[e_key]))
|
22
|
+
end
|
23
|
+
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
|
27
|
+
# Class method to compare the received body with the expected body.
|
28
|
+
# @param [Dynamic] expected_body The expected body.
|
29
|
+
# @param [Dynamic] actual_body The actual body.
|
30
|
+
# @param [Boolean, optional] check_values A flag which determines if we check values in dictionaries.
|
31
|
+
# @param [Boolean, optional] check_order A flag which determines if we check the order of array elements.
|
32
|
+
# @param [Boolean, optional] check_count A flag which determines if we check the count of array elements.
|
33
|
+
def self.match_body(expected_body,
|
34
|
+
actual_body,
|
35
|
+
check_values: false,
|
36
|
+
check_order: false,
|
37
|
+
check_count: false)
|
38
|
+
if expected_body.instance_of? Hash
|
39
|
+
return false unless actual_body.instance_of? Hash
|
40
|
+
for key in expected_body.keys
|
41
|
+
return false unless actual_body.keys.include? key
|
42
|
+
if check_values or expected_body[key].instance_of? Hash
|
43
|
+
return false unless match_body(expected_body[key],
|
44
|
+
actual_body[key],
|
45
|
+
check_values: check_values,
|
46
|
+
check_order: check_order,
|
47
|
+
check_count: check_count)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
elsif expected_body.instance_of? Array
|
51
|
+
return false unless actual_body.instance_of? Array
|
52
|
+
if check_count == true && (expected_body.length != actual_body.length)
|
53
|
+
return false
|
54
|
+
else
|
55
|
+
previous_matches = Array.new
|
56
|
+
expected_body.each.with_index do |expected_element, i|
|
57
|
+
matches = (actual_body.map.with_index do |received_element, j|
|
58
|
+
j if match_body(expected_element,
|
59
|
+
received_element,
|
60
|
+
check_values: check_values,
|
61
|
+
check_order: check_order,
|
62
|
+
check_count: check_count)
|
63
|
+
end).compact
|
64
|
+
return false if matches.length == 0
|
65
|
+
if check_order == true
|
66
|
+
return false if (i != 0 && matches.map{|x| previous_matches.map{|y| y > x}.all?}.all?)
|
67
|
+
previous_matches = matches
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
elsif expected_body != actual_body
|
72
|
+
return false
|
73
|
+
end
|
74
|
+
return true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|