pangea-sdk 0.0.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/.ignore +2 -0
- data/README.md +1 -0
- data/lib/pangea/client.rb +51 -0
- data/lib/pangea/errors.rb +113 -0
- data/lib/pangea/internal/transport/base_client.rb +346 -0
- data/lib/pangea/internal/transport/pooled_net_requester.rb +191 -0
- data/lib/pangea/internal/type/array_of.rb +119 -0
- data/lib/pangea/internal/type/base_model.rb +289 -0
- data/lib/pangea/internal/type/boolean.rb +44 -0
- data/lib/pangea/internal/type/converter.rb +228 -0
- data/lib/pangea/internal/type/hash_of.rb +166 -0
- data/lib/pangea/internal/type/request_parameters.rb +38 -0
- data/lib/pangea/internal/type/union.rb +66 -0
- data/lib/pangea/internal/type/unknown.rb +50 -0
- data/lib/pangea/internal/util.rb +429 -0
- data/lib/pangea/internal.rb +12 -0
- data/lib/pangea/models/ai_guard/classification_result.rb +33 -0
- data/lib/pangea/models/ai_guard/hardening_result.rb +27 -0
- data/lib/pangea/models/ai_guard/language_result.rb +20 -0
- data/lib/pangea/models/ai_guard/malicious_entity_result.rb +42 -0
- data/lib/pangea/models/ai_guard/prompt_injection_result.rb +33 -0
- data/lib/pangea/models/ai_guard/redact_entity_result.rb +43 -0
- data/lib/pangea/models/ai_guard/single_entity_result.rb +21 -0
- data/lib/pangea/models/ai_guard/text_guard_message_param.rb +19 -0
- data/lib/pangea/models/ai_guard/text_guard_params.rb +24 -0
- data/lib/pangea/models/ai_guard/text_guard_result.rb +308 -0
- data/lib/pangea/models/ai_guard/topic_result.rb +33 -0
- data/lib/pangea/models/pangea_response.rb +67 -0
- data/lib/pangea/request_options.rb +35 -0
- data/lib/pangea/services/ai_guard.rb +62 -0
- data/lib/pangea/version.rb +5 -0
- data/lib/pangea.rb +45 -0
- data/manifest.yaml +6 -0
- data/rbi/lib/pangea/client.rbi +25 -0
- data/rbi/lib/pangea/internal/internal.rbi +28 -0
- data/rbi/lib/pangea/internal/transport/base_client.rbi +18 -0
- data/rbi/lib/pangea/internal/type/array_of.rbi +66 -0
- data/rbi/lib/pangea/internal/type/base_model.rbi +33 -0
- data/rbi/lib/pangea/internal/type/boolean.rbi +46 -0
- data/rbi/lib/pangea/internal/type/converter.rbi +38 -0
- data/rbi/lib/pangea/internal/type/request_parameters.rbi +20 -0
- data/rbi/lib/pangea/internal/type/union.rbi +21 -0
- data/rbi/lib/pangea/internal/type/unknown.rbi +20 -0
- data/rbi/lib/pangea/internal.rbi +7 -0
- data/rbi/lib/pangea/models/ai_guard/text_guard_message_param.rbi +15 -0
- data/rbi/lib/pangea/models/ai_guard/text_guard_result.rbi +13 -0
- data/rbi/lib/pangea/models/pangea_response.rbi +31 -0
- data/rbi/lib/pangea/request_options.rbi +17 -0
- data/rbi/lib/pangea/services/ai_guard.rbi +28 -0
- data/rbi/lib/pangea/version.rbi +5 -0
- data/sig/pangea/client.rbs +12 -0
- data/sig/pangea/internal/transport/base_client.rbs +14 -0
- data/sig/pangea/internal/type/base_model.rbs +12 -0
- data/sig/pangea/internal/type/boolean.rbs +10 -0
- data/sig/pangea/internal/type/converter.rbs +9 -0
- data/sig/pangea/internal/type/request_parameters.rbs +15 -0
- data/sig/pangea/models/pangea_response.rbs +12 -0
- data/sig/pangea/models/text_guard_result.rbs +19 -0
- data/sig/pangea/request_options.rbs +34 -0
- data/sig/pangea/services/ai_guard.rbs +12 -0
- data/sig/pangea/version.rbs +3 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d1b347bd784b3a0bf8ce40adf2089ecfd694df533aba07788be0991b848785ad
|
4
|
+
data.tar.gz: f0cbdaaab93f69991b538caa35144ddafb671673eae269d3399a57eca6921d81
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ddf4fe35807a1f473a37a670bb713c03f92272e535d31ac304ba9138b53a2c18701621d88bf6b25183d40dc674d47e0a8a64aabd0919283146bc87703d71855c
|
7
|
+
data.tar.gz: ef2d077e6725d10b75f932ff69c98845eba47585e934ce498836008585be5a9da3df43c779d154c7ff3360118a71d4afcc356206bccfa5e5a75e8b674fc43dd6
|
data/.ignore
ADDED
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Pangea Ruby SDK
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pangea
|
4
|
+
class Client < Pangea::Internal::Transport::BaseClient
|
5
|
+
# Default per-request timeout.
|
6
|
+
DEFAULT_TIMEOUT_IN_SECONDS = 600.0
|
7
|
+
|
8
|
+
# Default max number of retries to attempt after a failed retryable request.
|
9
|
+
DEFAULT_MAX_RETRIES = 2
|
10
|
+
|
11
|
+
# Default initial retry delay in seconds.
|
12
|
+
# Overall delay is calculated using exponential backoff + jitter.
|
13
|
+
DEFAULT_INITIAL_RETRY_DELAY = 0.5
|
14
|
+
|
15
|
+
# @return [String]
|
16
|
+
attr_reader :api_token
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
# @return [Hash{String=>String}]
|
21
|
+
private def auth_headers
|
22
|
+
return {} if @api_token.nil?
|
23
|
+
|
24
|
+
{"authorization" => "Bearer #{@api_token}"}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Creates and returns a new client for interacting with the Pangea API.
|
28
|
+
#
|
29
|
+
# @param api_token [String]
|
30
|
+
# @param base_url [String]
|
31
|
+
# @param max_retries [Integer] Max number of retries to attempt after a
|
32
|
+
# failed retryable request.
|
33
|
+
def initialize(
|
34
|
+
api_token:,
|
35
|
+
base_url:,
|
36
|
+
initial_retry_delay: DEFAULT_INITIAL_RETRY_DELAY,
|
37
|
+
max_retries: DEFAULT_MAX_RETRIES,
|
38
|
+
timeout: DEFAULT_TIMEOUT_IN_SECONDS
|
39
|
+
)
|
40
|
+
@api_token = api_token&.to_s
|
41
|
+
|
42
|
+
super(
|
43
|
+
base_url: base_url,
|
44
|
+
initial_retry_delay: initial_retry_delay,
|
45
|
+
max_retries: max_retries,
|
46
|
+
headers: {},
|
47
|
+
timeout: timeout
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pangea
|
4
|
+
module Errors
|
5
|
+
class Error < StandardError
|
6
|
+
# @!parse
|
7
|
+
# # @return [StandardError, nil]
|
8
|
+
# attr_accessor :cause
|
9
|
+
end
|
10
|
+
|
11
|
+
class ConversionError < Pangea::Errors::Error
|
12
|
+
end
|
13
|
+
|
14
|
+
class APIError < Pangea::Errors::Error
|
15
|
+
# @return [URI::Generic]
|
16
|
+
attr_accessor :url
|
17
|
+
|
18
|
+
# @return [Integer, nil]
|
19
|
+
attr_accessor :status
|
20
|
+
|
21
|
+
# @return [Object, nil]
|
22
|
+
attr_accessor :body
|
23
|
+
|
24
|
+
# @return [String, nil]
|
25
|
+
attr_accessor :code
|
26
|
+
|
27
|
+
# @return [String, nil]
|
28
|
+
attr_accessor :param
|
29
|
+
|
30
|
+
# @return [String, nil]
|
31
|
+
attr_accessor :type
|
32
|
+
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
# @param url [URI::Generic]
|
36
|
+
# @param status [Integer, nil]
|
37
|
+
# @param body [Object, nil]
|
38
|
+
# @param request [nil]
|
39
|
+
# @param response [nil]
|
40
|
+
# @param message [String, nil]
|
41
|
+
def initialize(url:, status: nil, body: nil, request: nil, response: nil, message: nil)
|
42
|
+
@url = url
|
43
|
+
@status = status
|
44
|
+
@body = body
|
45
|
+
@request = request
|
46
|
+
@response = response
|
47
|
+
super(message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class APIConnectionError < Pangea::Errors::APIError
|
52
|
+
# @!parse
|
53
|
+
# # @return [nil]
|
54
|
+
# attr_accessor :status
|
55
|
+
|
56
|
+
# @!parse
|
57
|
+
# # @return [nil]
|
58
|
+
# attr_accessor :body
|
59
|
+
|
60
|
+
# @!parse
|
61
|
+
# # @return [nil]
|
62
|
+
# attr_accessor :code
|
63
|
+
|
64
|
+
# @!parse
|
65
|
+
# # @return [nil]
|
66
|
+
# attr_accessor :param
|
67
|
+
|
68
|
+
# @!parse
|
69
|
+
# # @return [nil]
|
70
|
+
# attr_accessor :type
|
71
|
+
|
72
|
+
# @api private
|
73
|
+
#
|
74
|
+
# @param url [URI::Generic]
|
75
|
+
# @param status [nil]
|
76
|
+
# @param body [nil]
|
77
|
+
# @param request [nil]
|
78
|
+
# @param response [nil]
|
79
|
+
# @param message [String, nil]
|
80
|
+
def initialize(
|
81
|
+
url:,
|
82
|
+
status: nil,
|
83
|
+
body: nil,
|
84
|
+
request: nil,
|
85
|
+
response: nil,
|
86
|
+
message: "Connection error."
|
87
|
+
)
|
88
|
+
super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class APITimeoutError < Pangea::Errors::APIConnectionError
|
93
|
+
# @api private
|
94
|
+
#
|
95
|
+
# @param url [URI::Generic]
|
96
|
+
# @param status [nil]
|
97
|
+
# @param body [nil]
|
98
|
+
# @param request [nil]
|
99
|
+
# @param response [nil]
|
100
|
+
# @param message [String, nil]
|
101
|
+
def initialize(
|
102
|
+
url:,
|
103
|
+
status: nil,
|
104
|
+
body: nil,
|
105
|
+
request: nil,
|
106
|
+
response: nil,
|
107
|
+
message: "Request timed out."
|
108
|
+
)
|
109
|
+
super
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,346 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pangea
|
4
|
+
module Internal
|
5
|
+
module Transport
|
6
|
+
# @api private
|
7
|
+
#
|
8
|
+
# @abstract
|
9
|
+
class BaseClient
|
10
|
+
PLATFORM_HEADERS =
|
11
|
+
{
|
12
|
+
"user-agent" => "pangea-ruby/#{Pangea::VERSION}"
|
13
|
+
}
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
# @return [Hash{String=>String}]
|
19
|
+
private def auth_headers = {}
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
# @param status [Integer, Pangea::Errors::APIConnectionError]
|
24
|
+
# @param stream [Enumerable<String>, nil]
|
25
|
+
def reap_connection!(status, stream:)
|
26
|
+
case status
|
27
|
+
in (..199) | (300..499)
|
28
|
+
stream&.each { next }
|
29
|
+
in Pangea::Errors::APIConnectionError | (500..)
|
30
|
+
Pangea::Internal::Util.close_fused!(stream)
|
31
|
+
else
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
# @param req [Hash{Symbol=>Object}]
|
38
|
+
#
|
39
|
+
# @raise [ArgumentError]
|
40
|
+
def validate!(req)
|
41
|
+
keys = [:method, :path, :query, :headers, :body, :unwrap, :page, :structure, :model, :options]
|
42
|
+
case req
|
43
|
+
in Hash
|
44
|
+
req.each_key do |k|
|
45
|
+
unless keys.include?(k)
|
46
|
+
raise ArgumentError.new("Request `req` keys must be one of #{keys}, got #{k.inspect}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
raise ArgumentError.new("Request `req` must be a Hash or RequestOptions, got #{req.inspect}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
# @return [Pangea::Internal::Transport::PooledNetRequester]
|
57
|
+
attr_accessor :requester
|
58
|
+
|
59
|
+
# @api private
|
60
|
+
#
|
61
|
+
# @param base_url [String]
|
62
|
+
# @param headers [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}]
|
63
|
+
# @param initial_retry_delay [Float]
|
64
|
+
# @param max_retries [Integer]
|
65
|
+
# @param timeout [Float]
|
66
|
+
def initialize(
|
67
|
+
base_url:,
|
68
|
+
headers: {},
|
69
|
+
initial_retry_delay: 0.0,
|
70
|
+
max_retries: 0,
|
71
|
+
timeout: 0.0
|
72
|
+
)
|
73
|
+
@requester = Pangea::Internal::Transport::PooledNetRequester.new
|
74
|
+
|
75
|
+
@base_url = Pangea::Internal::Util.parse_uri(base_url)
|
76
|
+
@headers = Pangea::Internal::Util.normalized_headers(
|
77
|
+
self.class::PLATFORM_HEADERS,
|
78
|
+
{
|
79
|
+
"accept" => "application/json",
|
80
|
+
"content-type" => "application/json"
|
81
|
+
},
|
82
|
+
headers
|
83
|
+
)
|
84
|
+
@initial_retry_delay = initial_retry_delay
|
85
|
+
@max_retries = max_retries
|
86
|
+
@timeout = timeout
|
87
|
+
end
|
88
|
+
|
89
|
+
# @api private
|
90
|
+
#
|
91
|
+
# @return [Hash{String=>String}]
|
92
|
+
private def auth_headers = {}
|
93
|
+
|
94
|
+
# @api private
|
95
|
+
#
|
96
|
+
# @param req [Hash{Symbol=>Object}] .
|
97
|
+
#
|
98
|
+
# @option req [Symbol] :method
|
99
|
+
#
|
100
|
+
# @option req [String, Array<String>] :path
|
101
|
+
#
|
102
|
+
# @option req [Hash{String=>Array<String>, String, nil}, nil] :query
|
103
|
+
#
|
104
|
+
# @option req [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}, nil] :headers
|
105
|
+
#
|
106
|
+
# @option req [Object, nil] :body
|
107
|
+
#
|
108
|
+
# @option req [Symbol, nil] :unwrap
|
109
|
+
#
|
110
|
+
# @option req [Class, nil] :page
|
111
|
+
#
|
112
|
+
# @option req [Class, nil] :stream
|
113
|
+
#
|
114
|
+
# @option req [Pangea::Internal::Type::Converter, Class, nil] :model
|
115
|
+
#
|
116
|
+
# @param opts [Hash{Symbol=>Object}] .
|
117
|
+
#
|
118
|
+
# @option opts [String, nil] :idempotency_key
|
119
|
+
#
|
120
|
+
# @option opts [Hash{String=>Array<String>, String, nil}, nil] :extra_query
|
121
|
+
#
|
122
|
+
# @option opts [Hash{String=>String, nil}, nil] :extra_headers
|
123
|
+
#
|
124
|
+
# @option opts [Object, nil] :extra_body
|
125
|
+
#
|
126
|
+
# @option opts [Integer, nil] :max_retries
|
127
|
+
#
|
128
|
+
# @option opts [Float, nil] :timeout
|
129
|
+
#
|
130
|
+
# @return [Hash{Symbol=>Object}]
|
131
|
+
private def build_request(req, opts)
|
132
|
+
method, uninterpolated_path = req.fetch_values(:method, :path)
|
133
|
+
|
134
|
+
path = Pangea::Internal::Util.interpolate_path(uninterpolated_path)
|
135
|
+
|
136
|
+
query = Pangea::Internal::Util.deep_merge(req[:query].to_h, opts[:extra_query].to_h)
|
137
|
+
|
138
|
+
headers = Pangea::Internal::Util.normalized_headers(
|
139
|
+
@headers,
|
140
|
+
auth_headers,
|
141
|
+
req[:headers].to_h,
|
142
|
+
opts[:extra_headers].to_h
|
143
|
+
)
|
144
|
+
|
145
|
+
if @idempotency_header &&
|
146
|
+
!headers.key?(@idempotency_header) &&
|
147
|
+
(!Net::HTTP::IDEMPOTENT_METHODS_.include?(method.to_s.upcase) || opts.key?(:idempotency_key))
|
148
|
+
headers[@idempotency_header] = opts.fetch(:idempotency_key) { generate_idempotency_key }
|
149
|
+
end
|
150
|
+
|
151
|
+
timeout = opts.fetch(:timeout, @timeout).to_f.clamp(0..)
|
152
|
+
|
153
|
+
headers.reject! { |_, v| v.to_s.empty? }
|
154
|
+
|
155
|
+
body =
|
156
|
+
case method
|
157
|
+
in :get | :head | :options | :trace
|
158
|
+
nil
|
159
|
+
else
|
160
|
+
Pangea::Internal::Util.deep_merge(*[req[:body], opts[:extra_body]].compact)
|
161
|
+
end
|
162
|
+
|
163
|
+
headers, encoded = Pangea::Internal::Util.encode_content(headers, body)
|
164
|
+
{
|
165
|
+
method: method,
|
166
|
+
url: Pangea::Internal::Util.join_parsed_uri(@base_url, {**req, path: path, query: query}),
|
167
|
+
headers: headers,
|
168
|
+
body: encoded,
|
169
|
+
max_retries: opts.fetch(:max_retries, @max_retries),
|
170
|
+
timeout: timeout
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
# @api private
|
175
|
+
#
|
176
|
+
# @param headers [Hash{String=>String}]
|
177
|
+
# @param retry_count [Integer]
|
178
|
+
#
|
179
|
+
# @return [Float]
|
180
|
+
private def retry_delay(headers, retry_count:)
|
181
|
+
span = Float(headers["retry-after-ms"], exception: false)&.then { _1 / 1000 }
|
182
|
+
return span if span
|
183
|
+
|
184
|
+
retry_header = headers["retry-after"]
|
185
|
+
return span if (span = Float(retry_header, exception: false))
|
186
|
+
|
187
|
+
span = retry_header&.then do
|
188
|
+
Time.httpdate(_1) - Time.now
|
189
|
+
rescue ArgumentError
|
190
|
+
nil
|
191
|
+
end
|
192
|
+
return span if span
|
193
|
+
|
194
|
+
scale = retry_count**2
|
195
|
+
jitter = 1 - (0.25 * rand)
|
196
|
+
(@initial_retry_delay * scale * jitter).clamp(0, @max_retry_delay)
|
197
|
+
end
|
198
|
+
|
199
|
+
# @api private
|
200
|
+
#
|
201
|
+
# @param request [Hash{Symbol=>Object}] .
|
202
|
+
#
|
203
|
+
# @option request [Symbol] :method
|
204
|
+
#
|
205
|
+
# @option request [URI::Generic] :url
|
206
|
+
#
|
207
|
+
# @option request [Hash{String=>String}] :headers
|
208
|
+
#
|
209
|
+
# @option request [Object] :body
|
210
|
+
#
|
211
|
+
# @option request [Integer] :max_retries
|
212
|
+
#
|
213
|
+
# @option request [Float] :timeout
|
214
|
+
#
|
215
|
+
# @param redirect_count [Integer]
|
216
|
+
#
|
217
|
+
# @param retry_count [Integer]
|
218
|
+
#
|
219
|
+
# @param send_retry_header [Boolean]
|
220
|
+
#
|
221
|
+
# @raise [Pangea::Errors::APIError]
|
222
|
+
# @return [Array(Integer, Net::HTTPResponse, Enumerable<String>)]
|
223
|
+
private def send_request(request, redirect_count:, retry_count:, send_retry_header:)
|
224
|
+
url, _headers, max_retries, timeout = request.fetch_values(:url, :headers, :max_retries, :timeout)
|
225
|
+
input = {**request.except(:timeout), deadline: Pangea::Internal::Util.monotonic_secs + timeout}
|
226
|
+
|
227
|
+
begin
|
228
|
+
status, response, stream = @requester.execute(input)
|
229
|
+
rescue Pangea::Errors::APIConnectionError => e
|
230
|
+
status = e
|
231
|
+
end
|
232
|
+
|
233
|
+
case status
|
234
|
+
in ..299
|
235
|
+
[status, response, stream]
|
236
|
+
in 300..399 if redirect_count >= self.class::MAX_REDIRECTS
|
237
|
+
self.class.reap_connection!(status, stream: stream)
|
238
|
+
|
239
|
+
message = "Failed to complete the request within #{self.class::MAX_REDIRECTS} redirects."
|
240
|
+
raise Pangea::Errors::APIConnectionError.new(url: url, response: response, message: message)
|
241
|
+
in 300..399
|
242
|
+
self.class.reap_connection!(status, stream: stream)
|
243
|
+
|
244
|
+
request = self.class.follow_redirect(request, status: status, response_headers: response)
|
245
|
+
send_request(
|
246
|
+
request,
|
247
|
+
redirect_count: redirect_count + 1,
|
248
|
+
retry_count: retry_count,
|
249
|
+
send_retry_header: send_retry_header
|
250
|
+
)
|
251
|
+
in Pangea::Errors::APIConnectionError if retry_count >= max_retries
|
252
|
+
raise status
|
253
|
+
in (400..) if retry_count >= max_retries || !self.class.should_retry?(status, headers: response)
|
254
|
+
decoded = Kernel.then do
|
255
|
+
Pangea::Internal::Util.decode_content(response, stream: stream, suppress_error: true)
|
256
|
+
ensure
|
257
|
+
self.class.reap_connection!(status, stream: stream)
|
258
|
+
end
|
259
|
+
|
260
|
+
raise Pangea::Errors::APIStatusError.for(
|
261
|
+
url: url,
|
262
|
+
status: status,
|
263
|
+
body: decoded,
|
264
|
+
request: nil,
|
265
|
+
response: response
|
266
|
+
)
|
267
|
+
in (400..) | Pangea::Errors::APIConnectionError
|
268
|
+
self.class.reap_connection!(status, stream: stream)
|
269
|
+
|
270
|
+
delay = retry_delay(response || {}, retry_count: retry_count)
|
271
|
+
sleep(delay)
|
272
|
+
|
273
|
+
send_request(
|
274
|
+
request,
|
275
|
+
redirect_count: redirect_count,
|
276
|
+
retry_count: retry_count + 1,
|
277
|
+
send_retry_header: send_retry_header
|
278
|
+
)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# Execute the request specified by `req`. This is the method that all resource
|
283
|
+
# methods call into.
|
284
|
+
#
|
285
|
+
# @overload request(method, path, query: {}, headers: {}, body: nil, unwrap: nil, page: nil, stream: nil, model: Pangea::Internal::Type::Unknown, options: {})
|
286
|
+
#
|
287
|
+
# @param method [Symbol]
|
288
|
+
#
|
289
|
+
# @param path [String, Array<String>]
|
290
|
+
#
|
291
|
+
# @param query [Hash{String=>Array<String>, String, nil}, nil]
|
292
|
+
#
|
293
|
+
# @param headers [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}, nil]
|
294
|
+
#
|
295
|
+
# @param body [Object, nil]
|
296
|
+
#
|
297
|
+
# @param unwrap [Symbol, nil]
|
298
|
+
#
|
299
|
+
# @param page [Class, nil]
|
300
|
+
#
|
301
|
+
# @param model [Pangea::Internal::Type::Converter, Class, nil]
|
302
|
+
#
|
303
|
+
# @param options [Pangea::RequestOptions, Hash{Symbol=>Object}, nil] .
|
304
|
+
#
|
305
|
+
# @option options [Hash{String=>Array<String>, String, nil}, nil] :extra_query
|
306
|
+
#
|
307
|
+
# @option options [Hash{String=>String, nil}, nil] :extra_headers
|
308
|
+
#
|
309
|
+
# @option options [Object, nil] :extra_body
|
310
|
+
#
|
311
|
+
# @option options [Integer, nil] :max_retries
|
312
|
+
#
|
313
|
+
# @option options [Float, nil] :timeout
|
314
|
+
#
|
315
|
+
# @raise [Pangea::Errors::APIError]
|
316
|
+
# @return [Object]
|
317
|
+
def request(req)
|
318
|
+
self.class.validate!(req)
|
319
|
+
model = req.fetch(:model) { Pangea::Internal::Type::Unknown }
|
320
|
+
opts = req[:options].to_h
|
321
|
+
Pangea::RequestOptions.validate!(opts)
|
322
|
+
request = build_request(req.except(:options), opts)
|
323
|
+
_url = request.fetch(:url)
|
324
|
+
|
325
|
+
_status, response, stream = send_request(
|
326
|
+
request,
|
327
|
+
redirect_count: 0,
|
328
|
+
retry_count: 0,
|
329
|
+
send_retry_header: false
|
330
|
+
)
|
331
|
+
|
332
|
+
decoded = Pangea::Internal::Util.decode_content(response, stream: stream)
|
333
|
+
case req
|
334
|
+
in {structure: Class => pr}
|
335
|
+
pr.new(response_data: decoded, model: model)
|
336
|
+
in {page: Class => page}
|
337
|
+
page.new(client: self, req: req, headers: response, page_data: decoded)
|
338
|
+
else
|
339
|
+
unwrapped = Pangea::Internal::Util.dig(decoded, req[:unwrap])
|
340
|
+
Pangea::Internal::Type::Converter.coerce(model, unwrapped)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|