# frozen_string_literal: true module Fiken # Base class for all errors raised by the gem. class Error < StandardError attr_reader :status, :body, :response def initialize(message = nil, status: nil, body: nil, response: nil) @status = status @body = body @response = response super(message || "Fiken API error (HTTP #{status})") end # Builds the most specific error subclass for an HTTP response. def self.from_response(status, body, response = nil) klass = STATUS_MAP[status] || (status >= 500 ? ServerError : self) klass.new(extract_message(body), status: status, body: body, response: response) end def self.extract_message(body) case body when String then body.empty? ? nil : body when Hash then hash_message(body) end end def self.hash_message(body) %w[message error_description error].each do |key| value = body[key] return value if value end messages = Array(body["validation_messages"]) messages.join(", ") unless messages.empty? end end # Raised when the request never reached Fiken (timeout, DNS, connection reset). class ConnectionError < Error; end # 400 class BadRequest < Error; end # 401 class Unauthorized < Error; end # 403 class Forbidden < Error; end # 404 class NotFound < Error; end # 406 class NotAcceptable < Error; end # 409 class Conflict < Error; end # 422 class UnprocessableEntity < Error; end # 429 class RateLimited < Error; end # 5xx class ServerError < Error; end class Error STATUS_MAP = { 400 => BadRequest, 401 => Unauthorized, 403 => Forbidden, 404 => NotFound, 406 => NotAcceptable, 409 => Conflict, 422 => UnprocessableEntity, 429 => RateLimited }.freeze end end