apimatic_core 0.1.0 → 0.2.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 +4 -4
- data/README.md +3 -5
- data/lib/apimatic-core/response_handler.rb +51 -29
- data/lib/apimatic-core/types/error_case.rb +53 -12
- data/lib/apimatic-core/utilities/api_helper.rb +58 -3
- data/lib/apimatic_core.rb +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43a0787b023f7ffa1b7c2a85955b951607f73678560cd1ae5ed5093a98e39787
|
4
|
+
data.tar.gz: 6753fbba0aeb9f496c4a926a226b55fe6aa6245b836ac027fd86d0b9cb295a12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3d9f9fe3b80a7980b632ac2a6b3fa34780aec0e94cefc7f8f0f1a4a632e99e0da7b2d66cf48f279356cee3486c4595e1ebe48764afcaa7344562732a91ea7f2
|
7
|
+
data.tar.gz: 125c4d4c4dadcd5c069b78eed5b703493e46e666575d1e926acb0e7a4b62099627ed97d8703b502e5e2d476edbf14e34f4438b4733198e00ca5b13a8378cbbf6
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# apimatic-core
|
2
|
-
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/apimatic_core)
|
3
4
|
[![Tests][test-badge]][test-url]
|
4
5
|
[![Linting][lint-badge]][lint-url]
|
5
|
-
[![Maintainability][maintainability-url]][code-climate-url]
|
6
6
|
[![Test Coverage][test-coverage-url]][code-climate-url]
|
7
7
|
[](https://github.com/rubocop/rubocop)
|
8
8
|
[![Licence][license-badge]][license-url]
|
@@ -86,10 +86,8 @@ gem 'apimatic_core'
|
|
86
86
|
| [`XmlHelper`](lib/apimatic-core/utilities/xml_helper.rb ) | A Helper class that holds utility methods for xml serialization and deserialization. |
|
87
87
|
|
88
88
|
## Links
|
89
|
-
* [apimatic_core_interfaces](
|
89
|
+
* [apimatic_core_interfaces](https://rubygems.org/gems/apimatic_core_interfaces)
|
90
90
|
|
91
|
-
[rubygems-version]: https://img.shields.io/pypi/v/apimatic-requests-client-adapter
|
92
|
-
[rubygems-apimatic-faraday-client-adapter-url]: https://pypi.org/project/apimatic-requests-client-adapter/
|
93
91
|
[test-badge]: https://github.com/apimatic/core-lib-ruby/actions/workflows/test-runner.yml/badge.svg
|
94
92
|
[test-url]: https://github.com/apimatic/core-lib-ruby/actions/workflows/test-runner.yml
|
95
93
|
[lint-badge]: https://github.com/apimatic/core-lib-ruby/actions/workflows/lint-runner.yml/badge.svg
|
@@ -44,13 +44,27 @@ module CoreLibrary
|
|
44
44
|
self
|
45
45
|
end
|
46
46
|
|
47
|
-
#
|
47
|
+
# Registers an entry with error message in the local errors hash.
|
48
48
|
# @param [String] error_code The error code to check against.
|
49
|
-
# @param [String]
|
49
|
+
# @param [String] error_message The reason for the exception.
|
50
50
|
# @param [ApiException] exception_type The type of the exception to raise.
|
51
51
|
# @return [ResponseHandler] An updated instance of ResponseHandler.
|
52
|
-
def local_error(error_code,
|
53
|
-
@local_errors[error_code.to_s] = ErrorCase.new
|
52
|
+
def local_error(error_code, error_message, exception_type)
|
53
|
+
@local_errors[error_code.to_s] = ErrorCase.new
|
54
|
+
.error_message(error_message)
|
55
|
+
.exception_type(exception_type)
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# Registers an entry with error template in the local errors hash.
|
60
|
+
# @param [String] error_code The error code to check against.
|
61
|
+
# @param [String] error_message_template The reason template for the exception.
|
62
|
+
# @param [ApiException] exception_type The type of the exception to raise.
|
63
|
+
# @return [ResponseHandler] An updated instance of ResponseHandler.
|
64
|
+
def local_error_template(error_code, error_message_template, exception_type)
|
65
|
+
@local_errors[error_code.to_s] = ErrorCase.new
|
66
|
+
.error_message_template(error_message_template)
|
67
|
+
.exception_type(exception_type)
|
54
68
|
self
|
55
69
|
end
|
56
70
|
|
@@ -186,34 +200,16 @@ module CoreLibrary
|
|
186
200
|
end
|
187
201
|
# rubocop:enable Style/OptionalBooleanParameter
|
188
202
|
|
189
|
-
# Validates the response provided and throws an error
|
190
|
-
# @param response The received response.
|
191
|
-
# @param global_errors Global errors hash.
|
203
|
+
# Validates the response provided and throws an error against the configured status code.
|
204
|
+
# @param [HttpResponse] response The received response.
|
205
|
+
# @param [Hash] global_errors Global errors hash.
|
206
|
+
# @raise [ApiException] Throws the exception when the response contains errors.
|
192
207
|
def validate(response, global_errors)
|
193
|
-
return unless response.status_code < 200 || response.status_code >
|
194
|
-
|
195
|
-
actual_status_code = response.status_code.to_s
|
196
|
-
|
197
|
-
contains_local_errors = (!@local_errors.nil? and !@local_errors[actual_status_code].nil?)
|
198
|
-
if contains_local_errors
|
199
|
-
error_case = @local_errors[actual_status_code]
|
200
|
-
raise error_case.get_exception_type.new error_case.get_description, response
|
201
|
-
end
|
202
|
-
|
203
|
-
contains_local_default_error = (!@local_errors.nil? and !@local_errors['default'].nil?)
|
204
|
-
if contains_local_default_error
|
205
|
-
error_case = @local_errors['default']
|
206
|
-
raise error_case.get_exception_type.new error_case.get_description, response
|
207
|
-
end
|
208
|
+
return unless response.status_code < 200 || response.status_code > 299
|
208
209
|
|
209
|
-
|
210
|
-
if contains_global_errors
|
211
|
-
error_case = global_errors[actual_status_code]
|
212
|
-
raise error_case.get_exception_type.new error_case.get_description, response
|
213
|
-
end
|
210
|
+
validate_against_error_cases(response, @local_errors)
|
214
211
|
|
215
|
-
|
216
|
-
raise error_case.get_exception_type.new error_case.get_description, response unless error_case.nil?
|
212
|
+
validate_against_error_cases(response, global_errors)
|
217
213
|
end
|
218
214
|
|
219
215
|
# Applies xml deserializer to the response.
|
@@ -265,5 +261,31 @@ module CoreLibrary
|
|
265
261
|
|
266
262
|
deserialized_value
|
267
263
|
end
|
264
|
+
|
265
|
+
# Validates the response against the provided error cases hash, if matches, it raises the exception.
|
266
|
+
# @param [HttpResponse] response The received response.
|
267
|
+
# @param [Hash] error_cases The error cases hash.
|
268
|
+
# @raise [ApiException] Raises the APIException when configured error code matches.
|
269
|
+
def validate_against_error_cases(response, error_cases)
|
270
|
+
actual_status_code = response.status_code.to_s
|
271
|
+
|
272
|
+
# Handling error case when configured as explicit error code
|
273
|
+
error_case = error_cases[actual_status_code]
|
274
|
+
error_case&.raise_exception(response)
|
275
|
+
|
276
|
+
# Handling error case when configured as explicit error codes range
|
277
|
+
default_range_entry = error_cases&.filter do |error_code, _|
|
278
|
+
error_code.match?("^#{actual_status_code[0]}XX$")
|
279
|
+
end
|
280
|
+
|
281
|
+
default_range_error_case = default_range_entry&.map { |_, error_case_instance| error_case_instance }
|
282
|
+
|
283
|
+
default_range_error_case[0].raise_exception(response) unless
|
284
|
+
default_range_error_case.nil? || default_range_error_case.empty?
|
285
|
+
|
286
|
+
# Handling default error case if configured
|
287
|
+
default_error_case = error_cases['default']
|
288
|
+
default_error_case&.raise_exception(response)
|
289
|
+
end
|
268
290
|
end
|
269
291
|
end
|
@@ -2,22 +2,25 @@ module CoreLibrary
|
|
2
2
|
# This data class represents the expected errors to be handled after the API call.
|
3
3
|
class ErrorCase
|
4
4
|
def initialize
|
5
|
-
@
|
5
|
+
@error_message = nil
|
6
|
+
@error_message_template = nil
|
6
7
|
@exception_type = nil
|
7
8
|
end
|
8
9
|
|
9
10
|
# The setter for the description of the error message.
|
10
|
-
# @param [String]
|
11
|
+
# @param [String] error_message The error message.
|
11
12
|
# @return [ErrorCase] An updated instance of ErrorCase.
|
12
|
-
def
|
13
|
-
@
|
13
|
+
def error_message(error_message)
|
14
|
+
@error_message = error_message
|
14
15
|
self
|
15
16
|
end
|
16
17
|
|
17
|
-
# The
|
18
|
-
# @
|
19
|
-
|
20
|
-
|
18
|
+
# The setter for the description of the error message.
|
19
|
+
# @param [String] error_message_template The error message template.
|
20
|
+
# @return [ErrorCase] An updated instance of ErrorCase.
|
21
|
+
def error_message_template(error_message_template)
|
22
|
+
@error_message_template = error_message_template
|
23
|
+
self
|
21
24
|
end
|
22
25
|
|
23
26
|
# The setter for the type of the exception to be thrown.
|
@@ -28,10 +31,48 @@ module CoreLibrary
|
|
28
31
|
self
|
29
32
|
end
|
30
33
|
|
31
|
-
#
|
32
|
-
#
|
33
|
-
|
34
|
-
|
34
|
+
# Getter for the error message for the exception case. This considers both error message
|
35
|
+
# and error template message. Error message template has the higher precedence over an error message.
|
36
|
+
# @param response The received http response.
|
37
|
+
# @return [String] The resolved exception message.
|
38
|
+
def get_error_message(response)
|
39
|
+
return _get_resolved_error_message_template(response) unless @error_message_template.nil?
|
40
|
+
|
41
|
+
@error_message
|
42
|
+
end
|
43
|
+
|
44
|
+
# Raises the exception for the current error case type.
|
45
|
+
# @param response The received response.
|
46
|
+
def raise_exception(response)
|
47
|
+
raise @exception_type.new get_error_message(response), response
|
48
|
+
end
|
49
|
+
|
50
|
+
# Updates all placeholders in the given message template with provided value.
|
51
|
+
# @param response The received http response.
|
52
|
+
# @return [String] The resolved template message.
|
53
|
+
def _get_resolved_error_message_template(response)
|
54
|
+
placeholders = @error_message_template.scan(/{\$.*?\}/)
|
55
|
+
|
56
|
+
status_code_placeholder = placeholders.select { |element| element == '{$statusCode}' }.uniq
|
57
|
+
header_placeholders = placeholders.select { |element| element.start_with?('{$response.header') }.uniq
|
58
|
+
body_placeholders = placeholders.select { |element| element.start_with?('{$response.body') }.uniq
|
59
|
+
|
60
|
+
# Handling response code placeholder
|
61
|
+
error_message_template = ApiHelper.resolve_template_placeholders(status_code_placeholder,
|
62
|
+
response.status_code.to_s,
|
63
|
+
@error_message_template)
|
64
|
+
|
65
|
+
# Handling response header placeholder
|
66
|
+
error_message_template = ApiHelper.resolve_template_placeholders(header_placeholders, response.headers,
|
67
|
+
error_message_template)
|
68
|
+
|
69
|
+
# Handling response body placeholder
|
70
|
+
response_payload = ApiHelper.json_deserialize(response.raw_body, true)
|
71
|
+
error_message_template = ApiHelper.resolve_template_placeholders_using_json_pointer(body_placeholders,
|
72
|
+
response_payload,
|
73
|
+
error_message_template)
|
74
|
+
|
75
|
+
error_message_template
|
35
76
|
end
|
36
77
|
end
|
37
78
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'erb'
|
2
|
+
require 'json-pointer'
|
3
|
+
|
2
4
|
module CoreLibrary
|
3
5
|
# API utility class involved in executing an API
|
4
6
|
class ApiHelper
|
@@ -230,9 +232,13 @@ module CoreLibrary
|
|
230
232
|
# @param [String] json A JSON string.
|
231
233
|
# rubocop:disable Style/OptionalBooleanParameter
|
232
234
|
def self.json_deserialize(json, should_symbolize = false)
|
233
|
-
|
234
|
-
|
235
|
-
|
235
|
+
return if json.nil?
|
236
|
+
|
237
|
+
begin
|
238
|
+
JSON.parse(json, symbolize_names: should_symbolize)
|
239
|
+
rescue StandardError
|
240
|
+
raise TypeError, 'Server responded with invalid JSON.'
|
241
|
+
end
|
236
242
|
end
|
237
243
|
# rubocop:enable Style/OptionalBooleanParameter
|
238
244
|
|
@@ -547,5 +553,54 @@ module CoreLibrary
|
|
547
553
|
TrueClass, FalseClass, Date,
|
548
554
|
DateTime, Array, Hash, Object]
|
549
555
|
end
|
556
|
+
|
557
|
+
# Updates all placeholders in the given message template with provided value.
|
558
|
+
# @param [String] placeholders The placeholders that need to be searched and replaced in the given template value.
|
559
|
+
# @param [String] value The dictionary containing the actual values to replace with.
|
560
|
+
# @param [String] template The template string containing placeholders.
|
561
|
+
# @@return [String] The resolved template value.
|
562
|
+
def self.resolve_template_placeholders_using_json_pointer(placeholders, value, template)
|
563
|
+
placeholders.each do |placeholder|
|
564
|
+
extracted_value = ''
|
565
|
+
if placeholder.include? '#'
|
566
|
+
# pick the 2nd chunk then remove the last character (i.e. `}`) of the string value
|
567
|
+
node_pointer = placeholder.split('#')[1].delete_suffix('}')
|
568
|
+
value_pointer = JsonPointer.new(value, node_pointer, symbolize_keys: true)
|
569
|
+
extracted_value = json_serialize(value_pointer.value) if value_pointer.exists?
|
570
|
+
elsif !value.nil?
|
571
|
+
extracted_value = json_serialize(value)
|
572
|
+
end
|
573
|
+
template.gsub!(placeholder, extracted_value)
|
574
|
+
end
|
575
|
+
|
576
|
+
template
|
577
|
+
end
|
578
|
+
|
579
|
+
# Updates all placeholders in the given message template with provided value.
|
580
|
+
# @param [List] placeholders The placeholders that need to be searched and replaced in the given template value.
|
581
|
+
# @param [Hash|String] values The value which refers to the actual values to replace with.
|
582
|
+
# @param [String] template The template string containing placeholders.
|
583
|
+
# @@return [String] The resolved template value.
|
584
|
+
def self.resolve_template_placeholders(placeholders, values, template)
|
585
|
+
values = values.map { |key, value| [key.to_s, value.to_s] }.to_h if values.is_a? Hash
|
586
|
+
|
587
|
+
placeholders.each do |placeholder|
|
588
|
+
extracted_value = ''
|
589
|
+
if values.is_a? Hash
|
590
|
+
# pick the last chunk then strip the last character (i.e. `}`) of the string value
|
591
|
+
key = if placeholder.include? '.'
|
592
|
+
placeholder.split('.')[-1].delete_suffix('}')
|
593
|
+
else
|
594
|
+
placeholder.delete_prefix('{').delete_suffix('}')
|
595
|
+
end
|
596
|
+
extracted_value = values[key] unless values[key].nil?
|
597
|
+
else
|
598
|
+
extracted_value = values unless values.nil?
|
599
|
+
end
|
600
|
+
template.gsub!(placeholder, extracted_value.to_s)
|
601
|
+
end
|
602
|
+
|
603
|
+
template
|
604
|
+
end
|
550
605
|
end
|
551
606
|
end
|
data/lib/apimatic_core.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apimatic_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- APIMatic Ltd.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: apimatic_core_interfaces
|
@@ -78,6 +78,20 @@ dependencies:
|
|
78
78
|
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: '1.0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: json-pointer
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :runtime
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
81
95
|
- !ruby/object:Gem::Dependency
|
82
96
|
name: faraday
|
83
97
|
requirement: !ruby/object:Gem::Requirement
|