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)