minato_ruby_api_client 0.2.8 → 0.2.9
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/Gemfile.lock +1 -1
- data/lib/minato_ruby_api_client/api_client.rb +1 -1
- data/lib/minato_ruby_api_client/api_error.rb +45 -1
- data/lib/minato_ruby_api_client/version.rb +1 -1
- data/spec/api_error_spec.rb +97 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 45411b504804ac12f92faecfe179060bdd00d565625671c8f6635b1b26ec66b0
|
|
4
|
+
data.tar.gz: 76665d77f7d0d036152d0389c7625185a0b244160803b8f614866fc1c6aacc78
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9b8ba15364e4b92dc7d485da1b6d8dae44b66f53058a42ab8be4073aff5d8d954180da03b4a0b6c59d82141ea1a8b6403c1c9b27bd246f9207538f230a5e0d4
|
|
7
|
+
data.tar.gz: a5d9bde60aeaccfbfee2dfe6e71c3bab5bf01d81bb3e3f069a019614dd45429fe6f776f46ca259ccf907278c20aab44a3ee84b96e4054f6783c144dcc39d73eb
|
data/Gemfile.lock
CHANGED
|
@@ -72,7 +72,7 @@ module MinatoRubyApiClient
|
|
|
72
72
|
unless response.success?
|
|
73
73
|
error = self.class.module_parent::ApiError.new(:status_code => response.status,
|
|
74
74
|
:res => response, :req => request)
|
|
75
|
-
error.caused_by = response.reason_phrase
|
|
75
|
+
error.caused_by = response.reason_phrase unless error.upstream_error?
|
|
76
76
|
|
|
77
77
|
fail error
|
|
78
78
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'minato_error_handler'
|
|
2
|
+
require 'json'
|
|
2
3
|
|
|
3
4
|
module MinatoRubyApiClient
|
|
4
5
|
class ApiError < MinatoErrorHandler::Errors::ExternalError
|
|
@@ -6,11 +7,54 @@ module MinatoRubyApiClient
|
|
|
6
7
|
|
|
7
8
|
def initialize(res: nil, req: nil, status_code: 500)
|
|
8
9
|
super(req: req, res: res)
|
|
10
|
+
@upstream_error = nil
|
|
9
11
|
@status_code = status_code
|
|
12
|
+
extracted_error, extracted_status = extract_upstream_error(res)
|
|
13
|
+
@upstream_error = extracted_error
|
|
14
|
+
@status_code = extracted_status || status_code
|
|
10
15
|
end
|
|
11
16
|
|
|
12
17
|
def message
|
|
13
|
-
"An error occurred while communicating with the API."
|
|
18
|
+
upstream_field("message") || "An error occurred while communicating with the API."
|
|
14
19
|
end
|
|
20
|
+
|
|
21
|
+
def code
|
|
22
|
+
upstream_field("code") || super
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def details
|
|
26
|
+
upstream_field("details") || super
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def caused_by
|
|
30
|
+
upstream_field("caused_by") || super
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def upstream_error?
|
|
34
|
+
!@upstream_error.nil? && !@upstream_error.empty?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def extract_upstream_error(res)
|
|
40
|
+
return [nil, nil] unless res.respond_to?(:body)
|
|
41
|
+
|
|
42
|
+
body = res.body
|
|
43
|
+
return [nil, nil] if body.nil? || body.empty?
|
|
44
|
+
|
|
45
|
+
parsed = JSON.parse(body)
|
|
46
|
+
return [nil, nil] unless parsed.is_a?(Hash)
|
|
47
|
+
|
|
48
|
+
upstream = parsed["error"] || parsed
|
|
49
|
+
return [nil, nil] unless upstream.is_a?(Hash) && upstream["code"]
|
|
50
|
+
|
|
51
|
+
[upstream, upstream["status_code"]&.to_i]
|
|
52
|
+
rescue JSON::ParserError
|
|
53
|
+
[nil, nil]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def upstream_field(key)
|
|
57
|
+
@upstream_error&.[](key)
|
|
58
|
+
end
|
|
15
59
|
end
|
|
16
60
|
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe MinatoRubyApiClient::ApiError do
|
|
4
|
+
def fake_response(body:, status: 422)
|
|
5
|
+
double("Faraday::Response", body: body, status: status)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
let(:upstream_error_body) do
|
|
9
|
+
JSON.generate({
|
|
10
|
+
"error" => {
|
|
11
|
+
"code" => "AccountSvc::Errors::AccountNotFound",
|
|
12
|
+
"message" => "Account not found",
|
|
13
|
+
"status_code" => 404,
|
|
14
|
+
"details" => { "account_id" => "abc-123" },
|
|
15
|
+
"caused_by" => "Couldn't find Account with id=abc-123"
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context "when the upstream response contains a Minato error payload" do
|
|
21
|
+
subject(:error) do
|
|
22
|
+
described_class.new(res: fake_response(body: upstream_error_body, status: 404))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "propagates the upstream code" do
|
|
26
|
+
expect(error.code).to eq("AccountSvc::Errors::AccountNotFound")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "propagates the upstream message" do
|
|
30
|
+
expect(error.message).to eq("Account not found")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "propagates the upstream status_code" do
|
|
34
|
+
expect(error.status_code).to eq(404)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "propagates the upstream details" do
|
|
38
|
+
expect(error.details).to eq({ "account_id" => "abc-123" })
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "propagates the upstream caused_by" do
|
|
42
|
+
expect(error.caused_by).to eq("Couldn't find Account with id=abc-123")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context "when the upstream response has no Minato error payload" do
|
|
47
|
+
subject(:error) do
|
|
48
|
+
described_class.new(res: fake_response(body: "Service Unavailable", status: 503), status_code: 503)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "falls back to the default code (class name)" do
|
|
52
|
+
expect(error.code).to eq("MinatoRubyApiClient::ApiError")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "falls back to the default message" do
|
|
56
|
+
expect(error.message).to eq("An error occurred while communicating with the API.")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "uses the provided status_code" do
|
|
60
|
+
expect(error.status_code).to eq(503)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context "when the upstream response body is empty" do
|
|
65
|
+
subject(:error) do
|
|
66
|
+
described_class.new(res: fake_response(body: "", status: 500), status_code: 500)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "falls back to default behavior" do
|
|
70
|
+
expect(error.code).to eq("MinatoRubyApiClient::ApiError")
|
|
71
|
+
expect(error.message).to eq("An error occurred while communicating with the API.")
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context "when the upstream response body is invalid JSON" do
|
|
76
|
+
subject(:error) do
|
|
77
|
+
described_class.new(res: fake_response(body: "<html>error</html>", status: 500), status_code: 500)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "falls back to default behavior without raising" do
|
|
81
|
+
expect(error.code).to eq("MinatoRubyApiClient::ApiError")
|
|
82
|
+
expect(error.message).to eq("An error occurred while communicating with the API.")
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe "#upstream_error?" do
|
|
87
|
+
it "returns true when the response contains a Minato error payload" do
|
|
88
|
+
error = described_class.new(res: fake_response(body: upstream_error_body, status: 404))
|
|
89
|
+
expect(error.upstream_error?).to be true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "returns false when the response has no Minato error payload" do
|
|
93
|
+
error = described_class.new(res: fake_response(body: "", status: 503), status_code: 503)
|
|
94
|
+
expect(error.upstream_error?).to be false
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minato_ruby_api_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ferreri
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-04-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -99,6 +99,7 @@ files:
|
|
|
99
99
|
- lib/minato_ruby_api_client/version.rb
|
|
100
100
|
- minato_ruby_api_client.gemspec
|
|
101
101
|
- spec/api_client_spec.rb
|
|
102
|
+
- spec/api_error_spec.rb
|
|
102
103
|
- spec/configuration_spec.rb
|
|
103
104
|
- spec/minato_ruby_api_client_spec.rb
|
|
104
105
|
- spec/spec_helper.rb
|
|
@@ -127,6 +128,7 @@ specification_version: 4
|
|
|
127
128
|
summary: A Minato ruby HTTP Client
|
|
128
129
|
test_files:
|
|
129
130
|
- spec/api_client_spec.rb
|
|
131
|
+
- spec/api_error_spec.rb
|
|
130
132
|
- spec/configuration_spec.rb
|
|
131
133
|
- spec/minato_ruby_api_client_spec.rb
|
|
132
134
|
- spec/spec_helper.rb
|