-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathapi_client_httpx_partial.mustache
134 lines (116 loc) · 5.02 KB
/
api_client_httpx_partial.mustache
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Call an API with given options.
#
# @return [Array<(Object, Integer, Hash)>] an array of 3 elements:
# the data deserialized from response body (could be nil), response status code and response headers.
def call_api(http_method, path, opts = {})
begin
response = build_request(http_method.to_s, path, opts)
if config.debugging
config.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"
end
response.raise_for_status
rescue HTTPX::HTTPError
fail ApiError.new(code: response.status,
response_headers: response.headers.to_h,
response_body: response.body.to_s),
Net::HTTP::STATUS_CODES.fetch(response.status, "HTTP Error (#{response.status})")
rescue HTTPX::TimeoutError
fail ApiError.new('Connection timed out')
rescue HTTPX::ConnectionError, HTTPX::ResolveError
fail ApiError.new('Connection failed')
end
if opts[:return_type] == 'File'
data = deserialize_file(response)
elsif opts[:return_type]
data = deserialize(response, opts[:return_type])
else
data = nil
end
return data, response.status, response.headers.to_h
end
# Builds the HTTP request
#
# @param [String] http_method HTTP method/verb (e.g. POST)
# @param [String] path URL path (e.g. /account/new)
# @option opts [Hash] :header_params Header parameters
# @option opts [Hash] :query_params Query parameters
# @option opts [Hash] :form_params Query parameters
# @option opts [Object] :body HTTP body (JSON/XML)
# @return [HTTPX::Request] A Request object
def build_request(http_method, path, opts = {})
url = build_request_url(path, opts)
header_params = @default_headers.merge(opts[:header_params] || {})
query_params = opts[:query_params] || {}
form_params = opts[:form_params] || {}
update_params_for_auth! header_params, query_params, opts[:auth_names]
if %w[POST PATCH PUT DELETE].include?(http_method)
body_params = build_request_body(header_params, form_params, opts[:body])
if config.debugging
config.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"
end
end
req_opts = {
:headers => HTTPX::Headers.new(header_params)
}
req_opts.merge!(body_params) if body_params
req_opts[:params] = query_params if query_params && !query_params.empty?
session.request(http_method, url, **req_opts)
end
# Builds the HTTP request body
#
# @param [Hash] header_params Header parameters
# @param [Hash] form_params Query parameters
# @param [Object] body HTTP body (JSON/XML)
# @return [Hash{Symbol => Object}] body options as HTTPX handles them
def build_request_body(header_params, form_params, body)
# http form
if header_params['Content-Type'] == 'application/x-www-form-urlencoded' ||
header_params['Content-Type'] == 'multipart/form-data'
header_params.delete('Content-Type') # httpx takes care of this
{ form: form_params }
elsif body
body.is_a?(String) ? { body: body } : { json: body }
end
end
def deserialize_file(response)
body = response.body
if @config.return_binary_data == true
# TODO: force response encoding
body.to_s
else
content_disposition = response.headers['content-disposition']
if content_disposition && content_disposition =~ /filename=/i
filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
prefix = sanitize_filename(filename)
else
prefix = 'download-'
end
prefix = prefix + '-' unless prefix.end_with?('-')
encoding = response.body.encoding
tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
response.copy_to(tempfile)
tempfile.close
@config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
"with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\
"will be deleted automatically with GC. It's also recommended to delete the temp file "\
"explicitly with `tempfile.delete`"
tempfile
end
end
def session
return @session if defined?(@session)
session = HTTPX.with(
ssl: @config.ssl,
timeout: ({ request_timeout: @config.timeout } if @config.timeout && @config.timeout.positive?),
origin: "#{@config.scheme}://#{@config.host}",
base_path: (@config.base_path.sub(/\/+\z/, '') if @config.base_path)
)
if @config.proxy
session = session.plugin(:proxy, proxy: @config.proxy)
end
if @config.username && @config.password
session = session.plugin(:basic_auth).basic_auth(@config.username, @config.password)
end
session = @config.configure(session)
@session = session
end