Class: Sendmux::Core::ErrorMapper

Inherits:
Object
  • Object
show all
Defined in:
lib/sendmux/core/errors.rb

Class Method Summary collapse

Class Method Details

.bool_at(value, key) ⇒ Object



83
84
85
86
# File 'lib/sendmux/core/errors.rb', line 83

def self.bool_at(value, key)
  child = value[key] if value.is_a?(Hash)
  [true, false].include?(child) ? child : nil
end

.default_retryable?(status) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/sendmux/core/errors.rb', line 98

def self.default_retryable?(status)
  status == 429 || (status.is_a?(Integer) && status >= 500)
end

.hash_at(value, key) ⇒ Object



73
74
75
76
# File 'lib/sendmux/core/errors.rb', line 73

def self.hash_at(value, key)
  child = value[key] if value.is_a?(Hash)
  child.is_a?(Hash) ? child : nil
end

.header(headers, name) ⇒ Object



93
94
95
96
# File 'lib/sendmux/core/errors.rb', line 93

def self.header(headers, name)
  pair = headers.find { |key, _value| key.downcase == name }
  pair&.last
end

.map(error) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/sendmux/core/errors.rb', line 25

def self.map(error)
  return error if error.is_a?(ApiError)

  headers = normalise_headers(error.respond_to?(:response_headers) ? error.response_headers : {})
  body = error.respond_to?(:response_body) ? error.response_body : nil
  payload = payload_from(body)
  detail = hash_at(payload, 'error') || {}
  status = status_from(error)

  ApiError.new(
    status: status,
    code: string_at(detail, 'code') || 'api_error',
    message: string_at(detail, 'message') || error.message || 'Sendmux API request failed',
    retryable: retryable(detail, status),
    request_id: request_id(payload, headers),
    param: string_at(detail, 'param'),
    errors: detail['errors'],
    response_body: body,
    response_headers: headers
  )
end

.normalise_headers(headers) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/sendmux/core/errors.rb', line 65

def self.normalise_headers(headers)
  return {} unless headers.respond_to?(:each)

  headers.each_with_object({}) do |(key, value), result|
    result[key.to_s] = value.is_a?(Array) ? value.join(', ') : value.to_s
  end
end

.payload_from(body) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/sendmux/core/errors.rb', line 53

def self.payload_from(body)
  return nil unless body.is_a?(String) && !body.empty?

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

.request_id(payload, headers) ⇒ Object



61
62
63
# File 'lib/sendmux/core/errors.rb', line 61

def self.request_id(payload, headers)
  string_at(hash_at(payload, 'meta'), 'request_id') || header(headers, 'x-request-id')
end

.retryable(detail, status) ⇒ Object



88
89
90
91
# File 'lib/sendmux/core/errors.rb', line 88

def self.retryable(detail, status)
  explicit = bool_at(detail, 'retryable')
  explicit.nil? ? default_retryable?(status) : explicit
end

.status_from(error) ⇒ Object



47
48
49
50
51
# File 'lib/sendmux/core/errors.rb', line 47

def self.status_from(error)
  return error.code if error.respond_to?(:code) && error.code.is_a?(Integer) && error.code.positive?

  nil
end

.string_at(value, key) ⇒ Object



78
79
80
81
# File 'lib/sendmux/core/errors.rb', line 78

def self.string_at(value, key)
  child = value[key] if value.is_a?(Hash)
  child.is_a?(String) && !child.empty? ? child : nil
end