Exception: TesoteSdk::ApiError

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

Overview

Server returned a usable HTTP response with an error.

Constant Summary collapse

CODE_REGISTRY =

Map error_code → typed subclass. Unknown codes fall back to ApiError.

{}

Instance Attribute Summary

Attributes inherited from Error

#attempts, #error_code, #error_id, #http_status, #request_id, #request_summary, #response_body, #retry_after

Class Method Summary collapse

Methods inherited from Error

#cause, #initialize, #inspect, #to_h

Constructor Details

This class inherits a constructor from TesoteSdk::Error

Class Method Details

.from_response(response, body, request_summary, attempts: 1) ⇒ Object

why: single dispatcher used by Transport — keeps mapping logic out of caller paths.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/tesote_sdk/errors.rb', line 76

def self.from_response(response, body, request_summary, attempts: 1)
  parsed = parse_body(body)
  envelope = parsed.is_a?(Hash) ? parsed : {}
  error_code = envelope['error_code']
  message = envelope['error'] || synthesize_message(response)
  error_id = envelope['error_id']
  retry_after_value = parse_retry_after(response, envelope['retry_after'])
  request_id = response['x-request-id'] || response['X-Request-Id']
  http_status = response.code.to_i

  klass = pick_class(http_status, error_code)
  klass.new(
    message,
    error_code: error_code,
    http_status: http_status,
    request_id: request_id,
    error_id: error_id,
    retry_after: retry_after_value,
    response_body: body,
    request_summary: request_summary,
    attempts: attempts
  )
end

.parse_body(body) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/tesote_sdk/errors.rb', line 107

def self.parse_body(body)
  return nil if body.nil? || body.empty?

  JSON.parse(body)
rescue JSON::ParserError
  nil
end

.parse_retry_after(response, envelope_value) ⇒ Object



119
120
121
122
123
124
125
126
# File 'lib/tesote_sdk/errors.rb', line 119

def self.parse_retry_after(response, envelope_value)
  header = response['retry-after'] || response['Retry-After']
  return Integer(header) if header && header.match?(/\A\d+\z/)
  return Integer(envelope_value) if envelope_value.is_a?(Integer)
  return Integer(envelope_value) if envelope_value.is_a?(String) && envelope_value.match?(/\A\d+\z/)

  nil
end

.pick_class(http_status, error_code) ⇒ Object



100
101
102
103
104
105
# File 'lib/tesote_sdk/errors.rb', line 100

def self.pick_class(http_status, error_code)
  return CODE_REGISTRY[error_code] if error_code && CODE_REGISTRY.key?(error_code)
  return ServiceUnavailableError if http_status == 503

  ApiError
end

.register(code, klass) ⇒ Object

rubocop:disable Style/MutableConstant – registered via .register at load time



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

def self.register(code, klass)
  CODE_REGISTRY[code] = klass
end

.synthesize_message(response) ⇒ Object



115
116
117
# File 'lib/tesote_sdk/errors.rb', line 115

def self.synthesize_message(response)
  "HTTP #{response.code} #{response.message}"
end