Class: TesoteSdk::Transport

Inherits:
Object
  • Object
show all
Defined in:
lib/tesote_sdk/transport.rb

Defined Under Namespace

Classes: RawResponse

Constant Summary collapse

DEFAULT_BASE_URL =
'https://equipo.tesote.com/api'.freeze
DEFAULT_OPEN_TIMEOUT =
5
DEFAULT_READ_TIMEOUT =
30
DEFAULT_MAX_ATTEMPTS =
3
DEFAULT_BASE_DELAY =
0.250
DEFAULT_MAX_DELAY =
8.0
MUTATING_METHODS =
%w[POST PUT PATCH DELETE].freeze
RETRYABLE_STATUSES =
[429, 502, 503, 504].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key:, version_segment:, base_url: DEFAULT_BASE_URL, user_agent: nil, open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT, max_attempts: DEFAULT_MAX_ATTEMPTS, base_delay: DEFAULT_BASE_DELAY, max_delay: DEFAULT_MAX_DELAY, logger: nil, cache_backend: nil, sleeper: nil, randomizer: nil) ⇒ Transport

Returns a new instance of Transport.

Raises:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/tesote_sdk/transport.rb', line 73

def initialize(api_key:,
               version_segment:,
               base_url: DEFAULT_BASE_URL,
               user_agent: nil,
               open_timeout: DEFAULT_OPEN_TIMEOUT,
               read_timeout: DEFAULT_READ_TIMEOUT,
               max_attempts: DEFAULT_MAX_ATTEMPTS,
               base_delay: DEFAULT_BASE_DELAY,
               max_delay: DEFAULT_MAX_DELAY,
               logger: nil,
               cache_backend: nil,
               sleeper: nil,
               randomizer: nil)
  raise ConfigError, 'api_key is required' if api_key.nil? || api_key.to_s.empty?
  raise ConfigError, 'version_segment is required' if version_segment.nil? || version_segment.to_s.empty?

  @api_key = api_key.to_s
  @version_segment = version_segment.to_s
  @base_url = base_url.to_s.sub(%r{/+\z}, '')
  @user_agent = user_agent || default_user_agent
  @open_timeout = open_timeout
  @read_timeout = read_timeout
  @max_attempts = max_attempts
  @base_delay = base_delay
  @max_delay = max_delay
  @logger = logger
  @cache_backend = cache_backend
  @sleeper = sleeper || ->(seconds) { sleep(seconds) }
  @randomizer = randomizer || ->(max) { Kernel.rand(max) }
  @last_rate_limit = nil
  @last_request_id = nil
end

Instance Attribute Details

#api_keyObject (readonly)

Returns the value of attribute api_key.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def api_key
  @api_key
end

#base_delayObject (readonly)

Returns the value of attribute base_delay.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def base_delay
  @base_delay
end

#base_urlObject (readonly)

Returns the value of attribute base_url.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def base_url
  @base_url
end

#cache_backendObject (readonly)

Returns the value of attribute cache_backend.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def cache_backend
  @cache_backend
end

#last_rate_limitObject

Returns the value of attribute last_rate_limit.



71
72
73
# File 'lib/tesote_sdk/transport.rb', line 71

def last_rate_limit
  @last_rate_limit
end

#last_request_idObject

Returns the value of attribute last_request_id.



71
72
73
# File 'lib/tesote_sdk/transport.rb', line 71

def last_request_id
  @last_request_id
end

#loggerObject (readonly)

Returns the value of attribute logger.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def logger
  @logger
end

#max_attemptsObject (readonly)

Returns the value of attribute max_attempts.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def max_attempts
  @max_attempts
end

#max_delayObject (readonly)

Returns the value of attribute max_delay.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def max_delay
  @max_delay
end

#open_timeoutObject (readonly)

Returns the value of attribute open_timeout.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def open_timeout
  @open_timeout
end

#read_timeoutObject (readonly)

Returns the value of attribute read_timeout.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def read_timeout
  @read_timeout
end

#user_agentObject (readonly)

Returns the value of attribute user_agent.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def user_agent
  @user_agent
end

#version_segmentObject (readonly)

Returns the value of attribute version_segment.



67
68
69
# File 'lib/tesote_sdk/transport.rb', line 67

def version_segment
  @version_segment
end

Instance Method Details

#request(method, path, query: nil, body: nil, opts: {}) ⇒ Object

opts:

:idempotency_key      → forwarded as Idempotency-Key (auto-gen for mutations)
:cache                → false to bypass; { ttl: int } to enable TTL cache
:extra_headers        → hash of additional headers


110
111
112
113
114
# File 'lib/tesote_sdk/transport.rb', line 110

def request(method, path, query: nil, body: nil, opts: {})
  method_upper = method.to_s.upcase
  uri = build_uri(path, query)
  execute_request(method_upper, uri, body, opts)
end

#request_raw(method, path, query: nil, body: nil, opts: {}) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/tesote_sdk/transport.rb', line 128

def request_raw(method, path, query: nil, body: nil, opts: {})
  method_upper = method.to_s.upcase
  uri = build_uri(path, query)
  request_summary = build_request_summary(method_upper, uri, body)
  response, body_str, attempts = perform_with_retries(method_upper, uri, body, opts, request_summary)

  record_rate_limit(response)
  @last_request_id = response['x-request-id'] || response['X-Request-Id']
  status = response.code.to_i

  if status >= 200 && status < 300
    return RawResponse.new(
      status: status,
      body: body_str,
      content_type: response['content-type'] || response['Content-Type'],
      content_disposition: response['content-disposition'] || response['Content-Disposition'],
      request_id: @last_request_id
    )
  end

  raise ApiError.from_response(response, body_str, request_summary, attempts: attempts)
end

#request_unversioned(method, path, query: nil, body: nil, opts: {}) ⇒ Object

why: GET /status and GET /whoami live at the API root, not under /v1 or /v2 — bypass the version_segment but reuse all cross-cutting.



118
119
120
121
122
# File 'lib/tesote_sdk/transport.rb', line 118

def request_unversioned(method, path, query: nil, body: nil, opts: {})
  method_upper = method.to_s.upcase
  uri = build_unversioned_uri(path, query)
  execute_request(method_upper, uri, body, opts)
end