rest-client-wrapper 3.0.1
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/README.md +484 -0
- data/lib/rest_client_wrapper.rb +33 -0
- data/lib/rest_client_wrapper/authenticators/auth.rb +30 -0
- data/lib/rest_client_wrapper/authenticators/basic.rb +45 -0
- data/lib/rest_client_wrapper/authenticators/custom.rb +61 -0
- data/lib/rest_client_wrapper/authenticators/oauth.rb +90 -0
- data/lib/rest_client_wrapper/authenticators/token.rb +43 -0
- data/lib/rest_client_wrapper/constants.rb +28 -0
- data/lib/rest_client_wrapper/exceptions.rb +37 -0
- data/lib/rest_client_wrapper/http.rb +66 -0
- data/lib/rest_client_wrapper/paginators/echo.rb +67 -0
- data/lib/rest_client_wrapper/paginators/echo_paginator.rb +67 -0
- data/lib/rest_client_wrapper/paginators/header_link.rb +78 -0
- data/lib/rest_client_wrapper/paginators/header_link_paginator.rb +78 -0
- data/lib/rest_client_wrapper/paginators/paginate.rb +32 -0
- data/lib/rest_client_wrapper/request.rb +75 -0
- data/lib/rest_client_wrapper/response.rb +34 -0
- data/lib/rest_client_wrapper/rest_client.rb +178 -0
- data/lib/rest_client_wrapper/version.rb +23 -0
- data/rest-client-wrapper.gemspec +51 -0
- data/spec/authenticators/oauth_spec.rb +103 -0
- data/spec/factories/request.rb +48 -0
- data/spec/factories/response.rb +47 -0
- data/spec/request_spec.rb +185 -0
- data/spec/rest_client_spec.rb +249 -0
- data/spec/spec_helper.rb +75 -0
- data/spec/support/factory_bot.rb +28 -0
- data/spec/support/stub_helper.rb +20 -0
- metadata +216 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
# Copyright (C) 2019 The University of Adelaide
|
2
|
+
#
|
3
|
+
# This file is part of Rest-Client-Wrapper.
|
4
|
+
#
|
5
|
+
# Rest-Client-Wrapper is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Rest-Client-Wrapper is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require_relative "paginate"
|
20
|
+
require_relative "../exceptions"
|
21
|
+
|
22
|
+
module RestClientWrapper
|
23
|
+
|
24
|
+
# Paginator
|
25
|
+
module Paginator
|
26
|
+
|
27
|
+
include Paginate
|
28
|
+
|
29
|
+
# Echo
|
30
|
+
class Echo
|
31
|
+
|
32
|
+
attr_accessor :rest_client
|
33
|
+
|
34
|
+
def initialize(limit: Paginate::DEFAULT_PAGINATION_PAGE_SIZE)
|
35
|
+
@rest_client = nil
|
36
|
+
@config = { limit: limit }
|
37
|
+
end
|
38
|
+
|
39
|
+
def paginate(http_method:, uri:, query_params: {}, headers: {}, data: false)
|
40
|
+
raise RestClientError.new("Client not set, unable to make API call", nil, nil) unless @rest_client
|
41
|
+
|
42
|
+
query_params.reverse_merge!(@config)
|
43
|
+
responses = []
|
44
|
+
loop do
|
45
|
+
response = @rest_client.make_request({ http_method: http_method, uri: uri, query_params: query_params, headers: headers })
|
46
|
+
block_given? ? yield(response) : (responses << response)
|
47
|
+
links = _pagination_links(response)
|
48
|
+
break unless links.key?(:offset)
|
49
|
+
|
50
|
+
query_params[:offset] = links[:offset]
|
51
|
+
end
|
52
|
+
return data ? responses.map(&:body).pluck(:data).flatten : responses
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def _pagination_links(response)
|
58
|
+
next_l = response&.body&.[](:next) || ""
|
59
|
+
next_h = Rack::Utils.parse_query(URI.parse(next_l)&.query)
|
60
|
+
return next_h.symbolize_keys!
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright (C) 2019 The University of Adelaide
|
2
|
+
#
|
3
|
+
# This file is part of Rest-Client-Wrapper.
|
4
|
+
#
|
5
|
+
# Rest-Client-Wrapper is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Rest-Client-Wrapper is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require_relative "paginate"
|
20
|
+
require_relative "../exceptions"
|
21
|
+
|
22
|
+
module RestClientWrapper
|
23
|
+
|
24
|
+
# Paginator
|
25
|
+
module Paginator
|
26
|
+
|
27
|
+
include Paginate
|
28
|
+
|
29
|
+
# HeaderLink
|
30
|
+
class HeaderLink
|
31
|
+
|
32
|
+
attr_accessor :rest_client
|
33
|
+
|
34
|
+
def initialize(per_page: Paginate::DEFAULT_PAGINATION_PAGE_SIZE)
|
35
|
+
@rest_client = nil
|
36
|
+
@config = { page: nil, per_page: per_page }
|
37
|
+
end
|
38
|
+
|
39
|
+
def paginate(http_method:, uri:, query_params: {}, headers: {}, data: false)
|
40
|
+
raise RestClientError.new("Client not set, unable to make API call", nil, nil) unless @rest_client
|
41
|
+
|
42
|
+
query_params.reverse_merge!(@config)
|
43
|
+
responses = []
|
44
|
+
loop.with_index(1) do |_, page|
|
45
|
+
query_params[:page] = page
|
46
|
+
response = @rest_client.make_request({ http_method: http_method, uri: uri, query_params: query_params, headers: headers })
|
47
|
+
block_given? ? yield(response) : (responses << response)
|
48
|
+
links = _pagination_links(response)
|
49
|
+
break unless links.key?(:next)
|
50
|
+
end
|
51
|
+
return data ? responses.map(&:body).flatten : responses
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def _pagination_links(response)
|
57
|
+
re_uri = "\<(.*?)\>".freeze
|
58
|
+
re_rel = "current|next|first|last".freeze
|
59
|
+
links_a = response&.headers&.[](:link)&.split(",") || []
|
60
|
+
links_h = {}
|
61
|
+
links_a.each do |rel_link|
|
62
|
+
link_parts = rel_link.split(";")
|
63
|
+
next unless link_parts.length == 2
|
64
|
+
|
65
|
+
uri_match = link_parts[0].match(re_uri)
|
66
|
+
rel_match = link_parts[1].match(re_rel)
|
67
|
+
next if (uri_match.nil? || rel_match.nil?) || (uri_match.captures.length != 1 || rel_match.length != 1)
|
68
|
+
|
69
|
+
links_h[rel_match[0]] = uri_match.captures[0]
|
70
|
+
end
|
71
|
+
return links_h.symbolize_keys!
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright (C) 2019 The University of Adelaide
|
2
|
+
#
|
3
|
+
# This file is part of Rest-Client-Wrapper.
|
4
|
+
#
|
5
|
+
# Rest-Client-Wrapper is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Rest-Client-Wrapper is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require_relative "paginate"
|
20
|
+
require_relative "../exceptions"
|
21
|
+
|
22
|
+
module RestClientWrapper
|
23
|
+
|
24
|
+
# Paginator
|
25
|
+
module Paginator
|
26
|
+
|
27
|
+
include Paginate
|
28
|
+
|
29
|
+
# HeaderLink
|
30
|
+
class HeaderLink
|
31
|
+
|
32
|
+
attr_accessor :rest_client
|
33
|
+
|
34
|
+
def initialize(per_page: Paginate::DEFAULT_PAGINATION_PAGE_SIZE)
|
35
|
+
@rest_client = nil
|
36
|
+
@config = { page: nil, per_page: per_page }
|
37
|
+
end
|
38
|
+
|
39
|
+
def paginate(http_method:, uri:, query_params: {}, headers: {}, data: false)
|
40
|
+
raise RestClientError.new("Client not set, unable to make API call", nil, nil) unless @rest_client
|
41
|
+
|
42
|
+
query_params.reverse_merge!(@config)
|
43
|
+
responses = []
|
44
|
+
loop.with_index(1) do |_, page|
|
45
|
+
query_params[:page] = page
|
46
|
+
response = @rest_client.make_request({ http_method: http_method, uri: uri, query_params: query_params, headers: headers })
|
47
|
+
block_given? ? yield(response) : (responses << response)
|
48
|
+
links = _pagination_links(response)
|
49
|
+
break unless links.key?(:next)
|
50
|
+
end
|
51
|
+
return data ? responses.map(&:body).flatten : responses
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def _pagination_links(response)
|
57
|
+
re_uri = "\<(.*?)\>".freeze
|
58
|
+
re_rel = "current|next|first|last".freeze
|
59
|
+
links_a = response&.headers&.[](:link)&.split(",") || []
|
60
|
+
links_h = {}
|
61
|
+
links_a.each do |rel_link|
|
62
|
+
link_parts = rel_link.split(";")
|
63
|
+
next unless link_parts.length == 2
|
64
|
+
|
65
|
+
uri_match = link_parts[0].match(re_uri)
|
66
|
+
rel_match = link_parts[1].match(re_rel)
|
67
|
+
next if (uri_match.nil? || rel_match.nil?) || (uri_match.captures.length != 1 || rel_match.length != 1)
|
68
|
+
|
69
|
+
links_h[rel_match[0]] = uri_match.captures[0]
|
70
|
+
end
|
71
|
+
return links_h.symbolize_keys!
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Copyright (C) 2019 The University of Adelaide
|
2
|
+
#
|
3
|
+
# This file is part of Rest-Client-Wrapper.
|
4
|
+
#
|
5
|
+
# Rest-Client-Wrapper is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Rest-Client-Wrapper is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
module RestClientWrapper
|
20
|
+
|
21
|
+
# Interface for paginators to implement
|
22
|
+
module Paginate
|
23
|
+
|
24
|
+
DEFAULT_PAGINATION_PAGE_SIZE = 1000
|
25
|
+
|
26
|
+
def paginate(_http_method:, _uri:, _payload:, _headers:, _data:)
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright (C) 2019 The University of Adelaide
|
2
|
+
#
|
3
|
+
# This file is part of Rest-Client-Wrapper.
|
4
|
+
#
|
5
|
+
# Rest-Client-Wrapper is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Rest-Client-Wrapper is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
module RestClientWrapper
|
20
|
+
|
21
|
+
# Request
|
22
|
+
class Request
|
23
|
+
|
24
|
+
attr_reader :uri, :headers, :http_method, :payload, :segment_params, :query_params
|
25
|
+
attr_writer :uri
|
26
|
+
|
27
|
+
DEFAULT_CONTENT_TYPE = { content_type: :json, accept: :json }.freeze # default content type for post and put requests
|
28
|
+
VALID_HTTP_METHODS = %i[get post put patch delete connect options trace].freeze
|
29
|
+
HTTP_METHOD_FOR_JSON = %i[post put patch].freeze
|
30
|
+
|
31
|
+
def initialize(http_method:, uri:, segment_params: {}, payload: {}, query_params: {}, headers: {}) # rubocop:disable Metrics/ParameterLists
|
32
|
+
@uri = uri
|
33
|
+
self.headers = headers
|
34
|
+
self.segment_params = segment_params
|
35
|
+
self.payload = payload
|
36
|
+
self.query_params = query_params
|
37
|
+
self.http_method = http_method
|
38
|
+
end
|
39
|
+
|
40
|
+
def http_method=(http_method)
|
41
|
+
raise TypeError, "Request http_method parameters is not a symbol" unless http_method.is_a?(Symbol)
|
42
|
+
raise ArgumentError, "Not a valid http method" unless VALID_HTTP_METHODS.include?(http_method)
|
43
|
+
|
44
|
+
headers[:content_type] = DEFAULT_CONTENT_TYPE[:content_type] unless headers.key?(:content_type) || !HTTP_METHOD_FOR_JSON.include?(http_method)
|
45
|
+
headers[:accept] = DEFAULT_CONTENT_TYPE[:accept] unless headers.key?(:accept) || !HTTP_METHOD_FOR_JSON.include?(http_method)
|
46
|
+
@http_method = http_method
|
47
|
+
end
|
48
|
+
|
49
|
+
def payload=(payload)
|
50
|
+
raise TypeError, "Request payload parameters is not a hash" unless payload.is_a?(Hash)
|
51
|
+
|
52
|
+
@payload = payload
|
53
|
+
end
|
54
|
+
|
55
|
+
def segment_params=(segment_params)
|
56
|
+
raise TypeError, "Request segment parameters is not a hash" unless segment_params.is_a?(Hash)
|
57
|
+
|
58
|
+
@segment_params = segment_params
|
59
|
+
end
|
60
|
+
|
61
|
+
def query_params=(query_params)
|
62
|
+
raise TypeError, "Request query parameters is not a hash" unless query_params.is_a?(Hash)
|
63
|
+
|
64
|
+
@query_params = query_params
|
65
|
+
end
|
66
|
+
|
67
|
+
def headers=(headers)
|
68
|
+
raise TypeError, "Request headers parameters is not a hash" unless headers.is_a?(Hash)
|
69
|
+
|
70
|
+
@headers.nil? ? @headers = headers : @headers.merge!(headers)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright (C) 2019 The University of Adelaide
|
2
|
+
#
|
3
|
+
# This file is part of Rest-Client-Wrapper.
|
4
|
+
#
|
5
|
+
# Rest-Client-Wrapper is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Rest-Client-Wrapper is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
module RestClientWrapper
|
20
|
+
|
21
|
+
# Response
|
22
|
+
class Response
|
23
|
+
|
24
|
+
attr_reader :headers, :body, :code
|
25
|
+
|
26
|
+
def initialize(headers, body, code)
|
27
|
+
@headers = headers
|
28
|
+
@body = body
|
29
|
+
@code = code
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# Copyright (C) 2019 The University of Adelaide
|
2
|
+
#
|
3
|
+
# This file is part of Rest-Client-Wrapper.
|
4
|
+
#
|
5
|
+
# Rest-Client-Wrapper is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# Rest-Client-Wrapper is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require "active_support"
|
20
|
+
require "active_support/core_ext"
|
21
|
+
require "json"
|
22
|
+
require "rack"
|
23
|
+
require "rest_client"
|
24
|
+
require_relative "exceptions"
|
25
|
+
require_relative "http"
|
26
|
+
|
27
|
+
module RestClientWrapper
|
28
|
+
|
29
|
+
# RestClient
|
30
|
+
class RestClient
|
31
|
+
|
32
|
+
include Http
|
33
|
+
|
34
|
+
attr_accessor :authenticator, :paginator
|
35
|
+
|
36
|
+
DEFAULT_RETRY = { max_retry: 0, wait: 0 }.freeze
|
37
|
+
DEFAULT_CONFIG = {
|
38
|
+
retries: {
|
39
|
+
401 => { max_retry: 1, wait: 0 }, # unauthorized
|
40
|
+
429 => { max_retry: 3, wait: 3 } # too many requests
|
41
|
+
}
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
def initialize(host:, config: {})
|
45
|
+
@host = host
|
46
|
+
@config = config
|
47
|
+
@retry_configs = {}.reverse_merge(DEFAULT_CONFIG[:retries])
|
48
|
+
|
49
|
+
@config[:retries]&.each do |k, v|
|
50
|
+
next unless Rack::Utils::HTTP_STATUS_CODES[k.to_i] # skip invalid codes
|
51
|
+
|
52
|
+
@retry_configs[k.to_i] = v.reverse_merge(DEFAULT_RETRY)
|
53
|
+
end
|
54
|
+
|
55
|
+
_reset_retries
|
56
|
+
end
|
57
|
+
|
58
|
+
def execute(request:)
|
59
|
+
_reset_retries
|
60
|
+
_validate_request(request)
|
61
|
+
_set_auth(request)
|
62
|
+
url = _build_uri(request)
|
63
|
+
|
64
|
+
loop do
|
65
|
+
access_token = @authenticator.is_a?(Authenticator::Oauth) ? @authenticator.access_token : nil
|
66
|
+
response_code = nil
|
67
|
+
|
68
|
+
begin
|
69
|
+
payload = Request::HTTP_METHOD_FOR_JSON.include?(request.http_method) ? request.payload.to_json : request.payload
|
70
|
+
request.headers[:params] = request.query_params
|
71
|
+
response = ::RestClient::Request.execute({ method: request.http_method, url: url, payload: payload, headers: request.headers })
|
72
|
+
response_code = response&.code
|
73
|
+
rescue StandardError => e
|
74
|
+
response_code = e.response&.code
|
75
|
+
# Any response that doesn't have a status of 200...207 will be raised as an exception from Rest-Client
|
76
|
+
raise RestClientError.new("API request encountered an unhandled exception", e.response, e) unless _retry?(response_code)
|
77
|
+
end
|
78
|
+
|
79
|
+
return Response.new(response.headers, _parse_response(response), response.code) if Http.success?(response_code)
|
80
|
+
raise RestClientNotSuccessful.new("API request was not successful", response) unless _retry?(response_code)
|
81
|
+
|
82
|
+
_wait_and_retry(response_code, access_token)
|
83
|
+
next
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def make_request(http_method:, uri:, payload: {}, query_params: {}, headers: {})
|
88
|
+
parsed_uri = URI.parse(uri)
|
89
|
+
|
90
|
+
raise ArgumentError, "URL host does not match config host of instance, unable to make API call" if parsed_uri.absolute? && @host.casecmp("#{ parsed_uri.scheme }://#{ parsed_uri.host }").nonzero?
|
91
|
+
|
92
|
+
uri = parsed_uri.absolute? ? parsed_uri.path : uri
|
93
|
+
request = Request.new({ http_method: http_method, uri: uri, payload: payload, query_params: query_params })
|
94
|
+
request.headers = headers
|
95
|
+
return self.execute({ request: request })
|
96
|
+
end
|
97
|
+
|
98
|
+
def make_request_for_pages(http_method:, uri:, query_params: {}, headers: {}, data: false)
|
99
|
+
raise RestClientError.new("Paginator not set, unable to make API call", nil, nil) unless @paginator
|
100
|
+
|
101
|
+
@paginator.rest_client ||= self
|
102
|
+
return @paginator.paginate({ http_method: http_method, uri: uri, query_params: query_params, headers: headers, data: data })
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def _set_auth(request)
|
108
|
+
return if @authenticator.nil?
|
109
|
+
|
110
|
+
auth = @authenticator.respond_to?(:generate_auth) ? @authenticator.generate_auth : {}
|
111
|
+
if @authenticator.is_a?(Authenticator::Custom)
|
112
|
+
case @authenticator.type
|
113
|
+
when :query_param
|
114
|
+
request.query_params.merge!(auth)
|
115
|
+
when :header
|
116
|
+
request.headers.merge!(auth)
|
117
|
+
end
|
118
|
+
else
|
119
|
+
request.headers.merge!(auth)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def _build_uri(request)
|
124
|
+
return format("#{ @host }#{ request.uri }", request.segment_params)
|
125
|
+
end
|
126
|
+
|
127
|
+
def _validate_request(request)
|
128
|
+
# Regex to find segments in uri with the pattern <segment_param>
|
129
|
+
url_segments = request.uri.scan(/\<(.*?)\>/).flatten
|
130
|
+
url_segments.each do |url_segment|
|
131
|
+
raise ArgumentError, "Segment parameter not provided for #{ url_segment }. URI #{ request.uri }" unless request.segment_params.include? url_segment.to_sym
|
132
|
+
end
|
133
|
+
return true
|
134
|
+
end
|
135
|
+
|
136
|
+
def _parse_response(response)
|
137
|
+
return nil unless response.respond_to?(:body)
|
138
|
+
|
139
|
+
parsed_body =
|
140
|
+
case MIME::Types[response&.headers&.[](:content_type)].first
|
141
|
+
when "application/json"
|
142
|
+
_parse_json(response)
|
143
|
+
else
|
144
|
+
response.body
|
145
|
+
end
|
146
|
+
|
147
|
+
return parsed_body
|
148
|
+
rescue StandardError => e
|
149
|
+
raise RestClientError.new("Response could not be parsed", response, e)
|
150
|
+
end
|
151
|
+
|
152
|
+
def _parse_json(response)
|
153
|
+
return { ok: true } if response.body == "ok".to_json # Handle special case for Echo delete responses
|
154
|
+
|
155
|
+
return JSON.parse(response.body, { object_class: Hash, symbolize_names: true })
|
156
|
+
rescue StandardError => e
|
157
|
+
raise RestClientError.new("Response could not be parsed as JSON", response, e)
|
158
|
+
end
|
159
|
+
|
160
|
+
def _reset_retries
|
161
|
+
@retry_configs.each_value { |v| v[:retry] = 0 }
|
162
|
+
end
|
163
|
+
|
164
|
+
def _retry?(response_code)
|
165
|
+
return true if @retry_configs.key?(response_code) && @retry_configs[response_code][:retry] < @retry_configs[response_code][:max_retry]
|
166
|
+
|
167
|
+
return false
|
168
|
+
end
|
169
|
+
|
170
|
+
def _wait_and_retry(response_code, access_token)
|
171
|
+
sleep(@retry_configs[response_code][:wait].to_f)
|
172
|
+
Authenticator::Oauth.authenticate({ client_id: @authenticator&.client_id, access_token: access_token }) if Http.unauthorized?(response_code) && @authenticator.is_a?(Authenticator::Oauth)
|
173
|
+
@retry_configs[response_code][:retry] += 1
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|