Class: EbayTrader::Request

Inherits:
Object
  • Object
show all
Defined in:
lib/ebay_trader/request.rb

Direct Known Subclasses

FetchToken, SessionID

Defined Under Namespace

Classes: Error

Constant Summary collapse

XMLNS =

eBay Trading API XML Namespace

'urn:ebay:apis:eBLBaseComponents'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(call_name, args = {}) {|xml_builder| ... } ⇒ Request

Construct a new eBay Trading API call.

Parameters:

  • call_name (String)

    the name of the API call, for example ‘GeteBayOfficialTime’.

  • args (Hash) (defaults to: {})

    optional configuration values for this request.

Options Hash (args):

  • :auth_token (String)

    the eBay Auth Token for the user submitting this request. If not defined the value of Configuration#auth_token will be assumed.

  • :ebay_site_id (Fixnum)

    Override the default eBay site ID in Configuration#ebay_site_id

  • :http_timeout (Fixnum)

    Override the default value of Configuration#http_timeout.

    This may be necessary for one-off calls such as UploadSiteHostedPictures which can take significantly longer.

  • :skip_type_casting (Array [String])

    An array of the keys for which the values should not get automatically type cast.

    Take for example the ‘BuyerUserID’ field. If someone has the username ‘123456’ the auto-type-casting would consider this to be a Fixnum. Adding ‘BuyerUserID’ to skip_type_casting list will ensure it remains a String.

  • :known_arrays (Array [String])

    a list of the names of elements that are known to have arrays of values. If defined here #response_hash will ensure array values in circumstances where there is only a single child element in the response XML.

    It is not necessary to use this feature, but doing so can simplify later stage logic as certain fields are guaranteed to be arrays. As there is no concept of arrays in XML it is not otherwise possible to determine if a field should be an array.

    An example case is when building a tree of nested categories. Some categories may only have one child category, but adding ‘Category’ or :category to this list will ensure the response_hash values is always an array. Hence it will not necessary to check if the elements of a category element is a Hash or an Array of Hashes when recursing through the data.

  • :xml_response (String)

    inject a pre-prepared XML response.

    If an XML response is given here the request will not actually be sent to eBay. Using this feature can dramatically speed up testing and also ensure you stay within eBay’s 5,000 requests per day throttling rate.

    It is also a useful feature for parsing locally cached/archived XML files.

  • :xml_tab_width (Fixnum)

    the number of spaces to indent child elements in the generated XML. The default is 0, meaning the XML is a single line string, but it’s nice to have the option of pretty-printing the XML for debugging.

Yields:

  • (xml_builder)

    a block describing the XML DOM.

Yield Parameters:

  • name (XMLBuilder)

    an XML builder node allowing customization of the request specific details.

Yield Returns:

  • (XMLBuilder)

    the same XML builder originally provided by the block.

Raises:



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/ebay_trader/request.rb', line 102

def initialize(call_name, args = {}, &block)
  time = Time.now
  @call_name  = call_name.freeze

  auth_token = %w"GetSessionID FetchToken".include?(call_name) ?
                  nil : (args[:auth_token] || EbayTrader.configuration.auth_token)
  @auth_token = auth_token.freeze

  @ebay_site_id = (args[:ebay_site_id] || EbayTrader.configuration.ebay_site_id).to_i
  @http_timeout = (args[:http_timeout] || EbayTrader.configuration.http_timeout).to_f
  @xml_tab_width = (args[:xml_tab_width] || 0).to_i

  @xml_response = args[:xml_response] || ''

  @skip_type_casting = args[:skip_type_casting] || []
  @skip_type_casting = @skip_type_casting.split if @skip_type_casting.is_a?(String)

  @known_arrays = args[:known_arrays] || []
  @known_arrays = @known_arrays.split if @known_arrays.is_a?(String)
  @known_arrays << 'errors'

  @message_id = nil
  if args.key?(:message_id)
    @message_id = (args[:message_id] == true) ? SecureRandom.uuid : args[:message_id].to_s
  end

  doc = XMLBuilder.new(tab_width: xml_tab_width).root("#{call_name}Request", xmlns: XMLNS) do
    unless auth_token.blank?
      RequesterCredentials do
        eBayAuthToken auth_token.to_s
      end
    end
    instance_eval(&block) if block_given?
    MessageID message_id unless message_id.nil?
  end
  @xml_request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n#{doc}"

  @http_response_code = 200
  submit if xml_response.blank?

  parsed_hash = parse(xml_response)
  root_key = parsed_hash.keys.first
  raise EbayTraderError, "Response '#{root_key}' does not match call name" unless root_key.gsub('_', '').eql?("#{call_name}Response".downcase)

  @response_hash = parsed_hash[root_key]
  @response_hash.freeze
  @response_time = Time.now - time

  @errors = []
  deep_find(:errors, []).each do |error|
    @errors << Error.new(error[:error_classification],
                         error[:severity_code],
                         error[:error_code],
                         error[:short_message],
                         error[:long_message])
  end
end

Instance Attribute Details

#auth_tokenObject (readonly)

Returns the value of attribute auth_token.



30
31
32
# File 'lib/ebay_trader/request.rb', line 30

def auth_token
  @auth_token
end

#call_nameObject (readonly)

Returns the value of attribute call_name.



29
30
31
# File 'lib/ebay_trader/request.rb', line 29

def call_name
  @call_name
end

#ebay_site_idObject (readonly)

Returns the value of attribute ebay_site_id.



31
32
33
# File 'lib/ebay_trader/request.rb', line 31

def ebay_site_id
  @ebay_site_id
end

#http_response_codeObject (readonly)

Returns the value of attribute http_response_code.



40
41
42
# File 'lib/ebay_trader/request.rb', line 40

def http_response_code
  @http_response_code
end

#http_timeoutObject (readonly)

Returns the value of attribute http_timeout.



39
40
41
# File 'lib/ebay_trader/request.rb', line 39

def http_timeout
  @http_timeout
end

#known_arraysObject (readonly)

Returns the value of attribute known_arrays.



35
36
37
# File 'lib/ebay_trader/request.rb', line 35

def known_arrays
  @known_arrays
end

#message_idObject (readonly)

Returns the value of attribute message_id.



32
33
34
# File 'lib/ebay_trader/request.rb', line 32

def message_id
  @message_id
end

#response_hashObject (readonly)

Returns the value of attribute response_hash.



33
34
35
# File 'lib/ebay_trader/request.rb', line 33

def response_hash
  @response_hash
end

#response_timeObject (readonly)

Returns the value of attribute response_time.



41
42
43
# File 'lib/ebay_trader/request.rb', line 41

def response_time
  @response_time
end

#skip_type_castingObject (readonly)

Returns the value of attribute skip_type_casting.



34
35
36
# File 'lib/ebay_trader/request.rb', line 34

def skip_type_casting
  @skip_type_casting
end

#xml_requestObject (readonly)

Returns the value of attribute xml_request.



37
38
39
# File 'lib/ebay_trader/request.rb', line 37

def xml_request
  @xml_request
end

#xml_responseObject (readonly)

Returns the value of attribute xml_response.



38
39
40
# File 'lib/ebay_trader/request.rb', line 38

def xml_response
  @xml_response
end

#xml_tab_widthObject (readonly)

Returns the value of attribute xml_tab_width.



36
37
38
# File 'lib/ebay_trader/request.rb', line 36

def xml_tab_width
  @xml_tab_width
end

Instance Method Details

#deep_find(path, default = nil) ⇒ Array

Recursively deep search through the #response_hash tree and return the first value matching the given path of node names. If path cannot be matched the value of default is returned.

Parameters:

  • path (Array [String|Symbol])

    an array of the keys defining the path to the node of interest.

  • default (Object) (defaults to: nil)

    the value to be returned if path cannot be matched.

Returns:

  • (Array)

    the first value found in path, or default.



233
234
235
# File 'lib/ebay_trader/request.rb', line 233

def deep_find(path, default = nil)
  @response_hash.deep_find(path, default)
end

#errorsArray[Error]

Get an array of Errors, excluding #warnings. This will be an empty array if there are no errors.

Returns:

  • (Array[Error])

    which have a severity_code of ‘Error’.



199
200
201
# File 'lib/ebay_trader/request.rb', line 199

def errors
  @errors.select { |error| error.error? }
end

#errors_and_warningsArray[Error]

Get an array of all #errors and #warnings.

Returns:



187
188
189
# File 'lib/ebay_trader/request.rb', line 187

def errors_and_warnings
  @errors
end

#failure?Boolean

Determine if this request has failed. This should return the opposite of #success?

Returns:

  • (Boolean)


168
169
170
# File 'lib/ebay_trader/request.rb', line 168

def failure?
  deep_find(:ack, '').downcase.eql?('failure')
end

#has_errors?Boolean

Determine if this request has generated any #errors, excluding #warnings.

Returns:

  • (Boolean)

    true if any errors present.



193
194
195
# File 'lib/ebay_trader/request.rb', line 193

def has_errors?
  errors.count > 0
end

#has_errors_or_warnings?Boolean

Determine if this request has generated any #errors or #warnings.

Returns:

  • (Boolean)

    true if errors or warnings present.



181
182
183
# File 'lib/ebay_trader/request.rb', line 181

def has_errors_or_warnings?
  has_errors? || has_warnings?
end

#has_warnings?Boolean

Determine if this request has generated any #warnings.

Returns:

  • (Boolean)

    true if warnings present.



205
206
207
# File 'lib/ebay_trader/request.rb', line 205

def has_warnings?
  warnings.count > 0
end

#partial_failure?Boolean

Determine if this response has partially failed. This eBay response is somewhat ambiguous, but generally means the request was processed by eBay, but warnings were generated.

Returns:

  • (Boolean)


175
176
177
# File 'lib/ebay_trader/request.rb', line 175

def partial_failure?
  deep_find(:ack, '').downcase.eql?('partialfailure')
end

#success?Boolean

Determine if this request has been successful. This should return the opposite of #failure?

Returns:

  • (Boolean)


162
163
164
# File 'lib/ebay_trader/request.rb', line 162

def success?
  deep_find(:ack, '').downcase.eql?('success')
end

#timestampTime

Get the timestamp of the response returned by eBay API. The timestamp indicates the time when eBay processed the request; it does not necessarily indicate the current eBay official eBay time. In particular, calls like GetCategories can return a cached response, so the time stamp may not be current.

Returns:

  • (Time)

    the response timestamp.



223
224
225
# File 'lib/ebay_trader/request.rb', line 223

def timestamp
  deep_find :timestamp
end

#to_json_sString

Get a String representation of the XML data hash in JSON notation.

Returns:

  • (String)

    pretty printed JSON.



253
254
255
256
# File 'lib/ebay_trader/request.rb', line 253

def to_json_s
  require 'json' unless defined? JSON
  puts JSON.pretty_generate(JSON.parse(@response_hash.to_json))
end

#to_s(indent = xml_tab_width) ⇒ String

Get a String representation of the response XML with indentation.

Returns:

  • (String)

    the response XML.



239
240
241
242
243
244
245
246
247
248
249
# File 'lib/ebay_trader/request.rb', line 239

def to_s(indent = xml_tab_width)
  xml = ''
  if defined? Ox
    ox_doc = Ox.parse(xml_response)
    xml = Ox.dump(ox_doc, indent: indent)
  else
    rexml_doc = REXML::Document.new(xml_response)
    rexml_doc.write(xml, indent)
  end
  xml
end

#warningsArray[Error]

Get an array of Errors representing warnings. This will be an empty array if there are no errors.

Returns:

  • (Array[Error])

    which have a severity_code of ‘Warning’.



211
212
213
# File 'lib/ebay_trader/request.rb', line 211

def warnings
  @errors.select { |error| error.warning? }
end