lib/nationbuilder/client.rb in nationbuilder-rb-1.1.0 vs lib/nationbuilder/client.rb in nationbuilder-rb-1.2.0
- old
+ new
@@ -1,12 +1,18 @@
class NationBuilder::Client
- def initialize(nation_name, api_key, base_url = 'https://:nation_name.nationbuilder.com')
+ def initialize(nation_name, api_key, opts = {})
@nation_name = nation_name
@api_key = api_key
- @base_url = base_url
@name_to_endpoint = {}
+ @base_url = opts[:base_url] || 'https://:nation_name.nationbuilder.com'
+ @retries = opts[:retries] || 8
+
+ if @retries < 1
+ raise 'A positive number of retries must be specified'
+ end
+
parsed_endpoints.each do |endpoint|
@name_to_endpoint[endpoint.name] = endpoint
end
end
@@ -29,10 +35,12 @@
def base_url
@base_url.gsub(':nation_name', @nation_name)
end
+ RETRY_DELAY = 0.1 # seconds
+
def raw_call(path, method, body = {}, args = {})
url = NationBuilder::URL.new(base_url).generate_url(path, args)
request_args = {
header: {
@@ -49,12 +57,11 @@
else
body[:access_token] = @api_key
request_args[:body] = JSON(body)
end
- set_response(HTTPClient.send(method, url, request_args))
- return parse_response_body(response)
+ perform_request_with_retries(method, url, request_args)
end
def call(endpoint_name, method_name, args={})
endpoint = self[endpoint_name]
method = endpoint[method_name]
@@ -62,25 +69,55 @@
method_args = method.method_args(args)
method.validate_args(method_args)
return raw_call(method.uri, method.http_method, nonmethod_args, args)
end
+ def perform_request_with_retries(method, url, request_args)
+ raw_response = HTTPClient.send(method, url, request_args)
+ parsed_response = nil
+
+ @retries.times do |i|
+ begin
+ parsed_response = parse_response_body(raw_response)
+ rescue NationBuilder::RateLimitedError
+ Kernel.sleep(RETRY_DELAY * 2**i)
+ rescue => e
+ raise e
+ else
+ break
+ end
+ end
+
+ set_response(raw_response)
+ parsed_response
+ end
+
def set_response(value)
Thread.current[:nationbuilder_rb_response] = value
end
+ # This getter is used for fetching the raw response
def response
Thread.current[:nationbuilder_rb_response]
end
- class ServerResponseError < StandardError; end
+ def classify_response_error(response)
+ case
+ when response.code == 429
+ return NationBuilder::RateLimitedError.new(response.body)
+ when response.code.to_s.start_with?('4')
+ return NationBuilder::ClientError.new(response.body)
+ when response.code.to_s.start_with?('5')
+ return NationBuilder::ServerError.new(response.body)
+ end
+ end
def parse_response_body(response)
- success = response.code.to_s.start_with?('2')
+ error = classify_response_error(response)
+ raise error if error
if response.header['Content-Type'].first != 'application/json'
- return {} if success
- raise ServerResponseError.new("Non-JSON content-type for server response: #{response.body}")
+ return nil
end
body = response.body.strip
return {} if body.length == 0
return JSON.parse(body)