def request(method, url = nil, options = {})
        options[:headers] = {'Content-Type' => 'application/json'}.merge(options[:headers] || {})
        options[:body] = options[:body].to_json if options[:body].is_a?(Hash)

        # Adopt Google's API erorr handling recommendation here:
        # https://developers.google.com/drive/handle-errors#implementing_exponential_backoff
        #
        # In essence, we try 5 times to perform the request. With each subsequent request,
        # we wait 2^n seconds plus a random number of milliseconds (no greater than 1 second)
        # until either we receive a successful response, or we run out of attempts.
        # If the Retry-After header is in the error response, we use whichever happens to be
        # greater, our calculated wait time, or the value in the Retry-After header.
        #
        # If development_mode is set to true, we only run the request once. This speeds up
        # development for those using this gem.
        attempt = 0
        max_attempts = GoogleAPI.development_mode ? 1 : 5
        while attempt < max_attempts
          response = access_token.send(method.to_sym, url, options)
          seconds_to_wait = [((2 ** attempt) + rand), response.headers['Retry-After'].to_i].max
          attempt += 1
          break if response.status < 400 || attempt == max_attempts
          GoogleAPI.logger.error "Request attempt ##{attempt} to #{url} failed for. Trying again in #{seconds_to_wait} seconds..."
          sleep seconds_to_wait
        end

        response.parsed || response
      end
def request(method, url = nil, options = {})
        options[:headers] = {'Content-Type' => 'application/json'}.merge(options[:headers] || {})
        options[:body] = options[:body].to_json if options[:body].is_a?(Hash)

        # Adopt Google's API erorr handling recommendation here:
        # https://developers.google.com/drive/handle-errors#implementing_exponential_backoff
        #
        # In essence, we try 5 times to perform the request. With each subsequent request,
        # we wait 2^n seconds plus a random number of milliseconds (no greater than 1 second)
        # until either we receive a successful response, or we run out of attempts.
        # If the Retry-After header is in the error response, we use whichever happens to be
        # greater, our calculated wait time, or the value in the Retry-After header.
        #
        # If development_mode is set to true, we only run the request once. This speeds up
        # development for those using this gem.
        attempt = 0
        max_attempts = GoogleAPI.development_mode ? 1 : 5
        while attempt < max_attempts
          response = access_token.send(method.to_sym, url, options)
          seconds_to_wait = [((2 ** attempt) + rand), response.headers['Retry-After'].to_i].max
          attempt += 1
          break if response.status < 400 || attempt == max_attempts
          GoogleAPI.logger.error "Request attempt ##{attempt} to #{url} failed for. Trying again in #{seconds_to_wait} seconds..."
          sleep seconds_to_wait
        end

        response.parsed || response
      end
A really important part of this class. The headers are injected here,
 and the body is transformed into a JSON'd string when necessary.
 We do exponential back-off for error responses, and return a parsed
 response body if present, the full Response object if not.