class Attio::Client

Handles authentication, retries, and error responses
HTTP client for making API requests to Attio

def base_url

def base_url
  "#{Attio.configuration.api_base}/#{Attio.configuration.api_version}"
end

def connection

def connection
  @connection ||= Faraday.new(
    url: base_url,
    headers: default_headers
  ) do |faraday|
    faraday.request :json
    faraday.response :json, content_type: /\bjson$/
    faraday.request :retry,
      max: Attio.configuration.max_retries,
      interval: 0.5,
      backoff_factor: 2,
      exceptions: [Faraday::TimeoutError, Faraday::ConnectionFailed]
    faraday.response :logger, Attio.configuration.logger if Attio.configuration.debug
    faraday.options.timeout = Attio.configuration.timeout
    faraday.options.open_timeout = Attio.configuration.open_timeout
    faraday.ssl.verify = Attio.configuration.verify_ssl_certs
    faraday.ssl.ca_file = Attio.configuration.ca_bundle_path if Attio.configuration.ca_bundle_path
  end
end

def default_headers

def default_headers
  {
    "Authorization" => "Bearer #{@api_key}",
    "User-Agent" => "Attio Ruby/#{Attio::VERSION}",
    "Accept" => "application/json",
    "Content-Type" => "application/json"
  }
end

def delete(path)

Raises:
  • (Error) - On API errors

Returns:
  • (Hash) - Parsed JSON response

Parameters:
  • path (String) -- The API endpoint path
def delete(path)
  request(:delete, path)
end

def get(path, params = {})

Raises:
  • (Error) - On API errors

Returns:
  • (Hash) - Parsed JSON response

Parameters:
  • params (Hash) -- Query parameters
  • path (String) -- The API endpoint path
def get(path, params = {})
  request(:get, path, params)
end

def handle_error(error)

def handle_error(error)
  case error
  when Faraday::TimeoutError
    raise TimeoutError, "Request timed out"
  when Faraday::ConnectionFailed
    raise ConnectionError, "Connection failed: #{error.message}"
  else
    raise ConnectionError, "Request failed: #{error.message}"
  end
end

def handle_response(response)

def handle_response(response)
  case response.status
  when 200..299
    response.body
  when 400
    error_message = response.body["error"] || response.body["message"] || "Bad request"
    raise BadRequestError.new("Bad request: #{error_message}", response_to_hash(response))
  when 401
    raise AuthenticationError.new("Authentication failed", response_to_hash(response))
  when 403
    raise ForbiddenError.new("Access forbidden", response_to_hash(response))
  when 404
    raise NotFoundError.new("Resource not found", response_to_hash(response))
  when 409
    raise ConflictError.new("Resource conflict", response_to_hash(response))
  when 422
    raise UnprocessableEntityError.new("Unprocessable entity", response_to_hash(response))
  when 429
    raise RateLimitError.new("Rate limit exceeded", response_to_hash(response))
  when 500..599
    raise ServerError.new("Server error", response_to_hash(response))
  else
    raise Error.new("Unexpected response status: #{response.status}", response_to_hash(response))
  end
end

def initialize(api_key: nil)

def initialize(api_key: nil)
  @api_key = api_key || Attio.configuration.api_key
  raise AuthenticationError, "No API key provided" unless @api_key
end

def patch(path, body = {})

Raises:
  • (Error) - On API errors

Returns:
  • (Hash) - Parsed JSON response

Parameters:
  • body (Hash) -- Request body to be sent as JSON
  • path (String) -- The API endpoint path
def patch(path, body = {})
  request(:patch, path, body)
end

def post(path, body = {})

Raises:
  • (Error) - On API errors

Returns:
  • (Hash) - Parsed JSON response

Parameters:
  • body (Hash) -- Request body to be sent as JSON
  • path (String) -- The API endpoint path
def post(path, body = {})
  request(:post, path, body)
end

def put(path, body = {})

Raises:
  • (Error) - On API errors

Returns:
  • (Hash) - Parsed JSON response

Parameters:
  • body (Hash) -- Request body to be sent as JSON
  • path (String) -- The API endpoint path
def put(path, body = {})
  request(:put, path, body)
end

def request(method, path, params_or_body = {})

def request(method, path, params_or_body = {})
  response = connection.send(method) do |req|
    req.url path
    case method
    when :get, :delete
      req.params = params_or_body if params_or_body.any?
    else
      req.body = params_or_body.to_json
    end
  end
  handle_response(response)
rescue Faraday::Error => e
  handle_error(e)
end

def response_to_hash(response)

def response_to_hash(response)
  {
    status: response.status,
    headers: response.headers,
    body: response.body
  }
end