lib/soapy_cake/response.rb
# frozen_string_literal: true
module SoapyCake
class Response
include Helper
SHORT_ELEMENT_DEPTH = 3
ELEMENTS_DEPTH = 5
attr_reader :body, :short_response, :time_converter
def initialize(body, short_response, time_converter)
@body = body
@short_response = short_response
@time_converter = time_converter
end
def to_enum
check_errors!
return typed_element(sax.at_depth(SHORT_ELEMENT_DEPTH).first) if short_response
Enumerator.new do |y|
sax.at_depth(ELEMENTS_DEPTH).each do |element|
y << typed_element(element)
end
end
end
def to_xml
check_errors!
(empty? ? [] : [body.to_s]).to_enum
end
private
def empty?
sax.at_depth(ELEMENTS_DEPTH).first.nil?
end
def typed_element(element)
walk_tree(element) do |value, key|
ResponseValue.new(key, value, time_converter).parse
end
end
def sax
@sax ||= Saxerator.parser(StringIO.new(body)) do |config|
config.symbolize_keys!
config.ignore_namespaces!
end
end
def check_errors!
# If we get a lot of data in our response, we can assume there was no error.
# This saves a lot of time because we don't have to scan the whole XML tree for errors.
return if body.length > 8192
error_check_fault!
return if error_check_special_case?
error_check_success!
end
def error_check_fault!
fault = sax.for_tag(:fault).first
raise RequestFailed, fault[:reason][:text] if fault
end
def error_check_success!
return if sax.for_tag(:success).first == 'true'
raise RateLimitError if error_message == 'Restricted'
raise RequestFailed, error_message
end
def error_check_special_case?
# Don't ask...
# As you might imagine, CAKE simply does not return the success element
# for this specific request. Also, this is the only request with a tag depth
# of 4, not 3 or 5 like ALL OTHER requests.
# BTW: There is a 10$ reward if anyone can find a worse designed API.
return true if sax.for_tag(:MediaType).count.positive?
false
end
def error_message
@error_message ||= sax.for_tag(:message).first || sax.for_tag(:Text).first || 'Unknown error'
end
end
end