Exception: Equipoise::ApiError

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(message = nil, status: nil, code: nil, details: nil, response: nil) ⇒ ApiError

Returns a new instance of ApiError.



48
49
50
51
52
53
54
# File 'lib/equipoise/errors.rb', line 48

def initialize(message = nil, status: nil, code: nil, details: nil, response: nil)
  super(message)
  @status   = status
  @code     = code
  @details  = details
  @response = response
end

Instance Attribute Details

#codeObject (readonly)

Returns the value of attribute code.



46
47
48
# File 'lib/equipoise/errors.rb', line 46

def code
  @code
end

#detailsObject (readonly)

Returns the value of attribute details.



46
47
48
# File 'lib/equipoise/errors.rb', line 46

def details
  @details
end

#responseObject (readonly)

Returns the value of attribute response.



46
47
48
# File 'lib/equipoise/errors.rb', line 46

def response
  @response
end

#statusObject (readonly)

Returns the value of attribute status.



46
47
48
# File 'lib/equipoise/errors.rb', line 46

def status
  @status
end

Class Method Details

.class_for(status) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/equipoise/errors.rb', line 89

def self.class_for(status)
  case status
  when 401 then AuthenticationError
  when 403 then ForbiddenError
  when 404 then NotFoundError
  when 409 then ConflictError
  when 422 then ValidationError
  when 429 then RateLimitError
  when 500..599 then ServerError
  else ApiError
  end
end

.default_message(status) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/equipoise/errors.rb', line 102

def self.default_message(status)
  {
    401 => "Unauthorized",
    403 => "Forbidden",
    404 => "Not found",
    409 => "Conflict",
    422 => "Validation failed",
    429 => "Rate limit exceeded"
  }.fetch(status) { status >= 500 ? "Server error" : "Request failed (#{status})" }
end

.from_response(response) ⇒ Object

Pick the subclass by HTTP status and parse the error envelope. Robust to an empty body (401) and the legacy string error body.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/equipoise/errors.rb', line 64

def self.from_response(response)
  status  = response.status
  body    = response.body
  payload = body.is_a?(Hash) ? body["error"] : nil

  code, message, details =
    if payload.is_a?(Hash)
      [payload["code"], payload["message"], payload["details"]]
    elsif payload.is_a?(String)
      [nil, payload, nil]
    else
      [nil, nil, nil]
    end

  message ||= default_message(status)
  klass     = class_for(status)

  if klass == RateLimitError
    klass.new(message, status: status, code: code, details: details,
                       response: response, retry_after: response.retry_after)
  else
    klass.new(message, status: status, code: code, details: details, response: response)
  end
end

Instance Method Details

#retryable?Boolean

429 + any 5xx are transient (back off and retry); every 4xx is a permanent client error the producer must fix (validation, auth, scope, not-found).

Returns:

  • (Boolean)


58
59
60
# File 'lib/equipoise/errors.rb', line 58

def retryable?
  status == 429 || status.to_i >= 500
end