lib/intercom/request.rb in intercom-3.9.0 vs lib/intercom/request.rb in intercom-3.9.2
- old
+ new
@@ -1,83 +1,73 @@
require 'cgi'
require 'net/https'
module Intercom
class Request
- attr_accessor :path, :net_http_method, :rate_limit_details, :handle_rate_limit
+ class << self
+ def get(path, params)
+ new(path, Net::HTTP::Get.new(append_query_string_to_url(path, params), default_headers))
+ end
- def initialize(path, net_http_method)
- self.path = path
- self.net_http_method = net_http_method
- self.handle_rate_limit = false
- end
+ def post(path, form_data)
+ new(path, method_with_body(Net::HTTP::Post, path, form_data))
+ end
- def set_common_headers(method, base_uri)
- method.add_field('AcceptEncoding', 'gzip, deflate')
- end
+ def delete(path, params)
+ new(path, method_with_body(Net::HTTP::Delete, path, params))
+ end
- def set_basic_auth(method, username, secret)
- method.basic_auth(CGI.unescape(username), CGI.unescape(secret))
- end
+ def put(path, form_data)
+ new(path, method_with_body(Net::HTTP::Put, path, form_data))
+ end
- def set_api_version(method, api_version)
- method.add_field('Intercom-Version', api_version)
- end
+ private def method_with_body(http_method, path, params)
+ request = http_method.send(:new, path, default_headers)
+ request.body = params.to_json
+ request["Content-Type"] = "application/json"
+ request
+ end
- def self.get(path, params)
- new(path, Net::HTTP::Get.new(append_query_string_to_url(path, params), default_headers))
- end
+ private def default_headers
+ {'Accept-Encoding' => 'gzip, deflate', 'Accept' => 'application/vnd.intercom.3+json', 'User-Agent' => "Intercom-Ruby/#{Intercom::VERSION}"}
+ end
- def self.post(path, form_data)
- new(path, method_with_body(Net::HTTP::Post, path, form_data))
+ private def append_query_string_to_url(url, params)
+ return url if params.empty?
+ query_string = params.map { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&')
+ url + "?#{query_string}"
+ end
end
- def self.delete(path, params)
- new(path, method_with_body(Net::HTTP::Delete, path, params))
+ def initialize(path, net_http_method)
+ self.path = path
+ self.net_http_method = net_http_method
+ self.handle_rate_limit = false
end
- def self.put(path, form_data)
- new(path, method_with_body(Net::HTTP::Put, path, form_data))
- end
+ attr_accessor :handle_rate_limit
- def self.method_with_body(http_method, path, params)
- request = http_method.send(:new, path, default_headers)
- request.body = params.to_json
- request["Content-Type"] = "application/json"
- request
- end
-
- def self.default_headers
- {'Accept-Encoding' => 'gzip, deflate', 'Accept' => 'application/vnd.intercom.3+json', 'User-Agent' => "Intercom-Ruby/#{Intercom::VERSION}"}
- end
-
- def client(uri, read_timeout:, open_timeout:)
- net = Net::HTTP.new(uri.host, uri.port)
- if uri.is_a?(URI::HTTPS)
- net.use_ssl = true
- net.verify_mode = OpenSSL::SSL::VERIFY_PEER
- net.ca_file = File.join(File.dirname(__FILE__), '../data/cacert.pem')
- end
- net.read_timeout = read_timeout
- net.open_timeout = open_timeout
- net
- end
-
def execute(target_base_url=nil, username:, secret: nil, read_timeout: 90, open_timeout: 30, api_version: nil)
retries = 3
base_uri = URI.parse(target_base_url)
set_common_headers(net_http_method, base_uri)
set_basic_auth(net_http_method, username, secret)
set_api_version(net_http_method, api_version) if api_version
begin
client(base_uri, read_timeout: read_timeout, open_timeout: open_timeout).start do |http|
begin
response = http.request(net_http_method)
+
set_rate_limit_details(response)
- decoded_body = decode_body(response)
- parsed_body = parse_body(decoded_body, response)
raise_errors_on_failure(response)
+
+ parsed_body = extract_response_body(response)
+
+ return nil if parsed_body.nil?
+
+ raise_application_errors_on_failure(parsed_body, response.code.to_i) if parsed_body['type'] == 'error.list'
+
parsed_body
rescue Intercom::RateLimitExceeded => e
if @handle_rate_limit
seconds_to_retry = (@rate_limit_details[:reset_at] - Time.now.utc).ceil
if (retries -= 1) < 0
@@ -96,59 +86,95 @@
rescue Timeout::Error
raise Intercom::ServiceConnectionError.new('Failed to connect to service [connection attempt timed out]')
end
end
- def decode_body(response)
- decode(response['content-encoding'], response.body)
- end
+ attr_accessor :path,
+ :net_http_method,
+ :rate_limit_details
- def parse_body(decoded_body, response)
- parsed_body = nil
- return parsed_body if decoded_body.nil? || decoded_body.strip.empty?
- begin
- parsed_body = JSON.parse(decoded_body)
- rescue JSON::ParserError => _
- raise_errors_on_failure(response)
+ private :path,
+ :net_http_method,
+ :rate_limit_details
+
+ private def client(uri, read_timeout:, open_timeout:)
+ net = Net::HTTP.new(uri.host, uri.port)
+ if uri.is_a?(URI::HTTPS)
+ net.use_ssl = true
+ net.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ net.ca_file = File.join(File.dirname(__FILE__), '../data/cacert.pem')
end
- raise_errors_on_failure(response) if parsed_body.nil?
- raise_application_errors_on_failure(parsed_body, response.code.to_i) if parsed_body['type'] == 'error.list'
- parsed_body
+ net.read_timeout = read_timeout
+ net.open_timeout = open_timeout
+ net
end
- def set_rate_limit_details(response)
+ private def extract_response_body(response)
+ decoded_body = decode(response['content-encoding'], response.body)
+
+ json_parse_response(decoded_body, response.code)
+ end
+
+ private def decode(content_encoding, body)
+ return body if (!body) || body.empty? || content_encoding != 'gzip'
+ Zlib::GzipReader.new(StringIO.new(body)).read.force_encoding("utf-8")
+ end
+
+ private def json_parse_response(str, code)
+ return nil if str.to_s.empty?
+
+ JSON.parse(str)
+ rescue JSON::ParserError
+ msg = <<~MSG.gsub(/[[:space:]]+/, " ").strip # #squish from ActiveSuppor
+ Expected a JSON response body. Instead got '#{str}'
+ with status code '#{code}'.
+ MSG
+
+ raise UnexpectedResponseError, msg
+ end
+
+ private def set_rate_limit_details(response)
rate_limit_details = {}
rate_limit_details[:limit] = response['X-RateLimit-Limit'].to_i if response['X-RateLimit-Limit']
rate_limit_details[:remaining] = response['X-RateLimit-Remaining'].to_i if response['X-RateLimit-Remaining']
rate_limit_details[:reset_at] = Time.at(response['X-RateLimit-Reset'].to_i) if response['X-RateLimit-Reset']
@rate_limit_details = rate_limit_details
end
- def decode(content_encoding, body)
- return body if (!body) || body.empty? || content_encoding != 'gzip'
- Zlib::GzipReader.new(StringIO.new(body)).read.force_encoding("utf-8")
+ private def set_common_headers(method, base_uri)
+ method.add_field('AcceptEncoding', 'gzip, deflate')
end
- def raise_errors_on_failure(res)
- if res.code.to_i.eql?(404)
+ private def set_basic_auth(method, username, secret)
+ method.basic_auth(CGI.unescape(username), CGI.unescape(secret))
+ end
+
+ private def set_api_version(method, api_version)
+ method.add_field('Intercom-Version', api_version)
+ end
+
+ private def raise_errors_on_failure(res)
+ code = res.code.to_i
+
+ if code == 404
raise Intercom::ResourceNotFound.new('Resource Not Found')
- elsif res.code.to_i.eql?(401)
+ elsif code == 401
raise Intercom::AuthenticationError.new('Unauthorized')
- elsif res.code.to_i.eql?(403)
+ elsif code == 403
raise Intercom::AuthenticationError.new('Forbidden')
- elsif res.code.to_i.eql?(429)
+ elsif code == 429
raise Intercom::RateLimitExceeded.new('Rate Limit Exceeded')
- elsif res.code.to_i.eql?(500)
+ elsif code == 500
raise Intercom::ServerError.new('Server Error')
- elsif res.code.to_i.eql?(502)
+ elsif code == 502
raise Intercom::BadGatewayError.new('Bad Gateway Error')
- elsif res.code.to_i.eql?(503)
+ elsif code == 503
raise Intercom::ServiceUnavailableError.new('Service Unavailable')
end
end
- def raise_application_errors_on_failure(error_list_details, http_code)
+ private def raise_application_errors_on_failure(error_list_details, http_code)
# Currently, we don't support multiple errors
error_details = error_list_details['errors'].first
error_code = error_details['type'] || error_details['code']
error_field = error_details['field']
parsed_http_code = (http_code > 0 ? http_code : nil)
@@ -196,20 +222,14 @@
else
raise Intercom::UnexpectedError.new(message_for_unexpected_error_with_type(error_details, parsed_http_code), error_context)
end
end
- def message_for_unexpected_error_with_type(error_details, parsed_http_code)
+ private def message_for_unexpected_error_with_type(error_details, parsed_http_code)
"The error of type '#{error_details['type']}' is not recognized. It occurred with the message: #{error_details['message']} and http_code: '#{parsed_http_code}'. Please contact Intercom with these details."
end
- def message_for_unexpected_error_without_type(error_details, parsed_http_code)
+ private def message_for_unexpected_error_without_type(error_details, parsed_http_code)
"An unexpected error occured. It occurred with the message: #{error_details['message']} and http_code: '#{parsed_http_code}'. Please contact Intercom with these details."
- end
-
- def self.append_query_string_to_url(url, params)
- return url if params.empty?
- query_string = params.map { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&')
- url + "?#{query_string}"
end
end
end