Exception: Nombaone::APIError
- Defined in:
- lib/nombaone/errors.rb,
lib/nombaone/errors.rb,
sig/nombaone/errors.rbs
Overview
A non-2xx response from the API. Carries everything the error envelope said: the stable #code to branch on, the #hint telling you how to fix it, the #doc_url into the error reference, per-field validation errors on 422s, and the #request_id to quote to support.
Subclasses are keyed by HTTP status so rescue reads naturally:
AuthenticationError, RateLimitError, ValidationError, ….
Branch on #code (stable) or the class (by HTTP status), never on the
message (it may be reworded).
Direct Known Subclasses
AuthenticationError, BadRequestError, ConflictError, NotFoundError, PermissionDeniedError, RateLimitError, ServerError, ValidationError
Constant Summary collapse
- CLASS_FOR_STATUS =
Subclass dispatch by HTTP status (429 is special-cased in
from_response). { 400 => BadRequestError, 401 => AuthenticationError, 403 => PermissionDeniedError, 404 => NotFoundError, 409 => ConflictError, 422 => ValidationError, }.freeze
- DEFAULT_CODE_FOR_STATUS =
The code to assume when the error body is missing or unusable.
{ 400 => ErrorCode::CLIENT_INVALID_REQUEST, 401 => ErrorCode::API_KEY_INVALID, 403 => ErrorCode::CLIENT_FORBIDDEN, 404 => ErrorCode::CLIENT_RESOURCE_NOT_FOUND, 409 => ErrorCode::CLIENT_CONFLICT, 422 => ErrorCode::CLIENT_VALIDATION_FAILED, 429 => ErrorCode::RATE_LIMIT_EXCEEDED, 502 => ErrorCode::SYSTEM_UPSTREAM_ERROR, 503 => ErrorCode::SYSTEM_UPSTREAM_ERROR, 504 => ErrorCode::SYSTEM_UPSTREAM_ERROR, }.freeze
Instance Attribute Summary collapse
-
#code ⇒ String
readonly
Stable machine-readable error code — branch on this.
-
#doc_url ⇒ String
readonly
Deep link to this code's entry in the error reference.
-
#fields ⇒ Hash{String => Array<String>}?
readonly
Per-field validation errors, present on 422 responses.
-
#hint ⇒ String
readonly
Actionable guidance from the API on what to do next.
-
#request_id ⇒ String?
readonly
The request id — include it when contacting support.
-
#status_code ⇒ Integer
readonly
HTTP status of the response.
Class Method Summary collapse
- .default_code_for_status(status) ⇒ String private
-
.from_response(status, body, headers) ⇒ APIError
private
Build the right APIError subclass from a raw response.
Instance Method Summary collapse
-
#initialize(message, status_code:, code:, hint: "", doc_url: "", fields: nil, request_id: nil) ⇒ APIError
constructor
private
A new instance of APIError.
Constructor Details
#initialize(message, status_code:, code:, hint: "", doc_url: "", fields: nil, request_id: nil) ⇒ APIError
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of APIError.
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/nombaone/errors.rb', line 130 def initialize(, status_code:, code:, hint: "", doc_url: "", fields: nil, request_id: nil) # Surface the hint in the raised message itself — the fix should arrive # with the failure, without a docs tab. super(hint.nil? || hint.empty? ? : "#{} — #{hint}") @status_code = status_code @code = code @hint = hint || "" @doc_url = doc_url || "" @fields = fields @request_id = request_id end |
Instance Attribute Details
#code ⇒ String (readonly)
Returns stable machine-readable error code — branch on this.
118 119 120 |
# File 'lib/nombaone/errors.rb', line 118 def code @code end |
#doc_url ⇒ String (readonly)
Returns deep link to this code's entry in the error reference.
122 123 124 |
# File 'lib/nombaone/errors.rb', line 122 def doc_url @doc_url end |
#fields ⇒ Hash{String => Array<String>}? (readonly)
Returns per-field validation errors, present on 422 responses.
125 126 127 |
# File 'lib/nombaone/errors.rb', line 125 def fields @fields end |
#hint ⇒ String (readonly)
Returns actionable guidance from the API on what to do next.
120 121 122 |
# File 'lib/nombaone/errors.rb', line 120 def hint @hint end |
#request_id ⇒ String? (readonly)
Returns the request id — include it when contacting support.
127 128 129 |
# File 'lib/nombaone/errors.rb', line 127 def request_id @request_id end |
#status_code ⇒ Integer (readonly)
Returns HTTP status of the response.
116 117 118 |
# File 'lib/nombaone/errors.rb', line 116 def status_code @status_code end |
Class Method Details
.default_code_for_status(status) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
177 178 179 |
# File 'lib/nombaone/errors.rb', line 177 def self.default_code_for_status(status) DEFAULT_CODE_FOR_STATUS.fetch(status, ErrorCode::SYSTEM_INTERNAL_ERROR) end |
.from_response(status, body, headers) ⇒ APIError
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Build the right Nombaone::APIError subclass from a raw response.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/nombaone/errors.rb', line 151 def self.from_response(status, body, headers) parsed = parse_error_body(body) code = parsed[:code] || default_code_for_status(status) = parsed[:message] || "Request failed with status #{status}" details = { status_code: status, code: code, hint: parsed[:hint] || "", doc_url: parsed[:doc_url] || "", request_id: parsed[:request_id] || headers["x-request-id"], fields: parsed[:fields], } klass = CLASS_FOR_STATUS[status] || (status >= 500 ? ServerError : APIError) return klass.new(, **details) unless status == 429 RateLimitError.new( , retry_after: numeric(headers["retry-after"]), limit: numeric(headers["x-ratelimit-limit"]), remaining: numeric(headers["x-ratelimit-remaining"]), **details, ) end |