Class: Payhub::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/payhub/client.rb

Overview

Synchronous PayHub client. Thread-safe — share one instance per process; internally each request opens a fresh Net::HTTP connection (keep-alive is delegated to the OS-level connection pool of the HTTP server tier).

Defined Under Namespace

Classes: HealthResource, Payments

Constant Summary collapse

DEFAULT_BASE_URL =
"https://app.payhub.ly"
DEFAULT_TIMEOUT =
30
DEFAULT_RETRIES =
2

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key, base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT, max_retries: DEFAULT_RETRIES, http_client: nil, user_agent_suffix: nil) ⇒ Client

Returns a new instance of Client.

Raises:

  • (ArgumentError)


24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/payhub/client.rb', line 24

def initialize(api_key, base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT,
  max_retries: DEFAULT_RETRIES, http_client: nil, user_agent_suffix: nil)
  raise ArgumentError, "PayHub API key must start with 'phk_'" unless api_key.is_a?(String) && api_key.start_with?("phk_")
  @api_key = api_key
  @base_url = base_url.sub(%r{/+$}, "")
  @timeout = timeout
  @max_retries = max_retries
  @http_client = http_client
  @user_agent = build_user_agent(user_agent_suffix)
  @payments = Payments.new(self)
  @health = HealthResource.new(self)
end

Instance Attribute Details

#healthObject (readonly)

Returns the value of attribute health.



22
23
24
# File 'lib/payhub/client.rb', line 22

def health
  @health
end

#paymentsObject (readonly)

Returns the value of attribute payments.



22
23
24
# File 'lib/payhub/client.rb', line 22

def payments
  @payments
end

Instance Method Details

#request(method, path, body: nil, idempotency_key: nil, retriable: true) ⇒ Object

Internal request helper used by resource classes.

Raises:



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/payhub/client.rb', line 38

def request(method, path, body: nil, idempotency_key: nil, retriable: true)
  attempts = retriable ? [@max_retries + 1, 1].max : 1
  last_err = nil
  attempts.times do |attempt|
    begin
      status, headers, raw = perform_request(method, path, body, idempotency_key)
    rescue Net::OpenTimeout, Net::ReadTimeout => e
      last_err = Errors::TimeoutError.new("payhub: timeout: #{e.message}")
    rescue SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET, EOFError, IOError => e
      last_err = Errors::ConnectionError.new("payhub: connection: #{e.message}")
    else
      if (200..299).cover?(status)
        return decode_2xx(raw)
      end
      err = build_api_error(status, raw, headers)
      if retriable && (status >= 500 || status == 429) && attempt + 1 < attempts
        wait = retry_after(headers) || backoff_seconds(attempt)
        sleep(wait)
        last_err = err
        next
      end
      raise err
    end
    sleep(backoff_seconds(attempt)) if attempt + 1 < attempts
  end
  raise last_err if last_err
  raise Errors::Error, "payhub: unreachable retry loop"
end