apimatic_core 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/apimatic_core.svg)](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
|
[![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](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
|