class RestClientWrapper::RestClient

RestClient

Constants

DEFAULT_CONFIG
DEFAULT_RETRY

Attributes

authenticator[RW]
paginator[RW]

Public Class Methods

new(host:, **config) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 44
def initialize(host:, **config)
  @host          = host
  @config        = config
  @retry_configs = {}.reverse_merge(DEFAULT_CONFIG[:retries])

  @config[:retries]&.each do |k, v|
    next unless Rack::Utils::HTTP_STATUS_CODES[k.to_i] # skip invalid codes

    @retry_configs[k.to_i] = v.reverse_merge(DEFAULT_RETRY)
  end

  _reset_retries
end

Public Instance Methods

execute(request:) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 58
def execute(request:)
  _reset_retries
  _validate_request(request)
  _set_auth(request)
  url = _build_uri(request)

  loop do
    access_token = @authenticator.is_a?(Authenticator::Oauth) ? @authenticator.access_token : nil
    response_code = nil

    begin
      payload = Request::HTTP_METHOD_FOR_JSON.include?(request.http_method) && request.headers[:content_type] == :json ? request.payload.to_json : request.payload
      request.headers[:params] = request.query_params
      response = ::RestClient::Request.execute({ method: request.http_method, url: url, payload: payload, headers: request.headers })
      response_code = response&.code
    rescue StandardError => e
      response_code = e.response&.code
      # Any response that doesn't have a status of 200...207 will be raised as an exception from Rest-Client
      raise RestClientError.new("API request encountered an unhandled exception", e.response, e) unless _retry?(response_code)
    end

    return Response.new(response.headers, _parse_response(response), response.code) if Http.success?(response_code)
    raise RestClientNotSuccessful.new("API request was not successful", response) unless _retry?(response_code)

    _wait_and_retry(response_code, access_token)
    next
  end
end
execute_paginated_request(request:, data: true) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 87
def execute_paginated_request(request:, data: true)
  return self.make_request_for_pages({ http_method: request.http_method, uri: request.uri, segment_params: request.segment_params, query_params: request.query_params, headers: request.headers, data: data }) # rubocop:disable Metrics/LineLength
end
make_request(http_method:, uri:, payload: {}, segment_params: {}, query_params: {}, headers: {}) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 91
def make_request(http_method:, uri:, payload: {}, segment_params: {}, query_params: {}, headers: {})
  request = Request.new({ http_method: http_method, uri: uri, payload: payload, segment_params: segment_params, query_params: query_params })
  request.headers = headers
  return self.execute({ request: request })
end
make_request_for_pages(http_method:, uri:, segment_params: {}, query_params: {}, headers: {}, data: false) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 97
def make_request_for_pages(http_method:, uri:, segment_params: {}, query_params: {}, headers: {}, data: false)
  raise RestClientError.new("Paginator not set, unable to make API call", nil, nil) unless @paginator

  @paginator.rest_client ||= self
  return @paginator.paginate({ http_method: http_method, uri: uri, segment_params: segment_params, query_params: query_params, headers: headers, data: data })
end

Private Instance Methods

_build_uri(request) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 122
def _build_uri(request)
  uri = format(request.uri, request.segment_params)
  parsed_uri = URI.parse(uri)
  raise ArgumentError, "URL host does not match config host of instance, unable to make API call" if parsed_uri.absolute? && @host.casecmp("#{ parsed_uri.scheme }://#{ parsed_uri.host }").nonzero?

  return parsed_uri.absolute? ? uri : "#{ @host }#{ uri }"
end
_parse_json(response) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 155
def _parse_json(response)
  return { ok: true } if response.body == "ok".to_json # Handle special case for Echo delete responses

  return JSON.parse(response.body, { object_class: Hash, symbolize_names: true })
rescue StandardError
  return response.body
end
_parse_response(response) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 139
def _parse_response(response)
  return nil unless response.respond_to?(:body)

  parsed_body =
    case MIME::Types[response&.headers&.[](:content_type)].first
    when "application/json"
      _parse_json(response)
    else
      response.body
    end

  return parsed_body
rescue StandardError => e
  raise RestClientError.new("Response could not be parsed", response, e)
end
_reset_retries() click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 163
def _reset_retries
  @retry_configs.each_value { |v| v[:retry] = 0 }
end
_retry?(response_code) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 167
def _retry?(response_code)
  return true if @retry_configs.key?(response_code) && @retry_configs[response_code][:retry] < @retry_configs[response_code][:max_retry]

  return false
end
_set_auth(request) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 106
def _set_auth(request)
  return if @authenticator.nil?

  auth = @authenticator.respond_to?(:generate_auth) ? @authenticator.generate_auth : {}
  if @authenticator.is_a?(Authenticator::Custom)
    case @authenticator.type
    when :query_param
      request.query_params.merge!(auth)
    when :header
      request.headers.merge!(auth)
    end
  else
    request.headers.merge!(auth)
  end
end
_validate_request(request) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 130
def _validate_request(request)
  # Regex to find segments in uri with the pattern <segment_param>
  url_segments = request.uri.scan(/<(.*?)>/).flatten
  url_segments.each do |url_segment|
    raise ArgumentError, "Segment parameter not provided for #{ url_segment }. URI #{ request.uri }" unless request.segment_params.include? url_segment.to_sym
  end
  return true
end
_wait_and_retry(response_code, access_token) click to toggle source
# File lib/rest_client_wrapper/rest_client.rb, line 173
def _wait_and_retry(response_code, access_token)
  sleep(@retry_configs[response_code][:wait].to_f)
  Authenticator::Oauth.authenticate({ client_id: @authenticator&.client_id, access_token: access_token }) if Http.unauthorized?(response_code) && @authenticator.is_a?(Authenticator::Oauth)
  @retry_configs[response_code][:retry] += 1
end