require 'digest'
require 'net/http'
require 'uri'
module Underpass
class Client
def self.perform(request, max_retries: nil)
max_retries = Underpass.configuration.max_retries if max_retries.nil?
cache_key = Digest::SHA256.hexdigest(request.to_query)
cached = Underpass.cache&.fetch(cache_key)
return cached if cached
response = perform_with_retries(request, max_retries)
Underpass.cache&.store(cache_key, response)
response
end
def self.perform_with_retries(request, max_retries)
retries = 0
loop do
response = post_request(request)
return response if response.code.to_i == 200
retries = handle_error(response, retries, max_retries)
sleep(2**retries)
end
end
private_class_method :perform_with_retries
def self.post_request(request)
Net::HTTP.post_form(
URI(Underpass.configuration.api_endpoint),
data: request.to_query
)
end
private_class_method :post_request
def self.handle_error(response, retries, max_retries)
status_code = response.code.to_i
error_class = { 429 => RateLimitError, 504 => TimeoutError }[status_code] || ApiError
raise build_error(error_class, response.body, status_code) if error_class == ApiError
retries += 1
raise build_error(error_class, response.body, status_code) if retries > max_retries
retries
end
private_class_method :handle_error
def self.build_error(error_class, body, status_code)
parsed = ErrorParser.parse(body, status_code)
error_class.new(
parsed[:message],
code: parsed[:code],
error_message: parsed[:message],
details: parsed[:details],
http_status: status_code
)
end
private_class_method :build_error
end
end