class Redd::APIClient

The class for API clients.

Constants

API_ENDPOINT

The endpoint to make API requests to.

Attributes

access[RW]

@return [APIClient] the access the client uses

Public Class Methods

new(auth, endpoint: API_ENDPOINT, user_agent: USER_AGENT, limit_time: 1, max_retries: 5, auto_refresh: true) click to toggle source

Create a new API client with an auth strategy. @param auth [AuthStrategies::AuthStrategy] the auth strategy to use @param endpoint [String] the API endpoint @param user_agent [String] the user agent to send @param limit_time [Integer] the minimum number of seconds between each request @param max_retries [Integer] number of times to retry requests that may succeed if retried @param auto_refresh [Boolean] automatically refresh access token if nearing expiration

Calls superclass method
# File lib/redd/api_client.rb, line 25
def initialize(auth, endpoint: API_ENDPOINT, user_agent: USER_AGENT, limit_time: 1,
               max_retries: 5, auto_refresh: true)
  super(endpoint: endpoint, user_agent: user_agent)

  @auth          = auth
  @access        = nil
  @max_retries   = max_retries
  @failures      = 0
  @error_handler = Utilities::ErrorHandler.new
  @rate_limiter  = Utilities::RateLimiter.new(limit_time)
  @unmarshaller  = Utilities::Unmarshaller.new(self)
  @auto_refresh  = auto_refresh
end

Public Instance Methods

authenticate(*args) click to toggle source

Authenticate the client using the provided auth.

# File lib/redd/api_client.rb, line 40
def authenticate(*args)
  @access = @auth.authenticate(*args)
end
model(verb, path, options = {}) click to toggle source
# File lib/redd/api_client.rb, line 59
def model(verb, path, options = {})
  # XXX: make unmarshal explicit in methods?
  unmarshal(send(verb, path, options).body)
end
refresh() click to toggle source

Refresh the access currently in use.

# File lib/redd/api_client.rb, line 45
def refresh
  @access = @auth.refresh(@access)
end
request(verb, path, raw: false, params: {}, **options) click to toggle source

Makes a request, ensuring not to break the rate limit by sleeping. @see Client#request

Calls superclass method
# File lib/redd/api_client.rb, line 66
def request(verb, path, raw: false, params: {}, **options)
  # Make sure @access is populated by a valid access
  ensure_access_is_valid
  # Setup base API params and make request
  api_params = { api_type: 'json', raw_json: 1 }.merge(params)

  # This loop is retried @max_retries number of times until it succeeds
  handle_retryable_errors do
    response = @rate_limiter.after_limit { super(verb, path, params: api_params, **options) }
    # Raise errors if encountered at the API level.
    response_error = @error_handler.check_error(response, raw: raw)
    raise response_error unless response_error.nil?
    # All done, return the response
    response
  end
end
revoke() click to toggle source

Revoke the current access and remove it from the client.

# File lib/redd/api_client.rb, line 50
def revoke
  @auth.revoke(@access)
  @access = nil
end
unmarshal(object) click to toggle source
# File lib/redd/api_client.rb, line 55
def unmarshal(object)
  @unmarshaller.unmarshal(object)
end

Private Instance Methods

connection() click to toggle source
Calls superclass method
# File lib/redd/api_client.rb, line 106
def connection
  super.auth("Bearer #{@access.access_token}")
end
ensure_access_is_valid() click to toggle source

Makes sure a valid access is present, raising an error if nil

# File lib/redd/api_client.rb, line 86
def ensure_access_is_valid
  # If access is nil, panic
  raise 'client access is nil, try calling #authenticate' if @access.nil?
  # Refresh access if auto_refresh is enabled
  refresh if @auto_refresh && @access.permanent? && @access.expired?
end
handle_retryable_errors() { || ... } click to toggle source
# File lib/redd/api_client.rb, line 93
def handle_retryable_errors
  response = yield
rescue Redd::ServerError, HTTP::TimeoutError => e
  # FIXME: maybe only retry GET requests, for obvious reasons?
  @failures += 1
  raise e if @failures > @max_retries
  warn "Redd got a #{e.class.name} error (#{e.message}), retrying..."
  retry
else
  @failures = 0
  response
end