class Soaspec::RestHandler

Wraps around Savon client defining default values dependent on the soap request

Attributes

api_username[RW]

User used in making API calls

Public Class Methods

new(name = self.class.to_s, options = {}) click to toggle source

Setup object to handle communicating with a particular SOAP WSDL @param [Hash] options Options defining REST request. base_url, default_hash

Calls superclass method Soaspec::ExchangeHandler::new
# File lib/soaspec/exchange_handlers/rest_handler.rb, line 31
def initialize(name = self.class.to_s, options = {})
  raise "Base URL not set! Please set in class with 'base_url' method" unless base_url_value

  if name.is_a?(Hash) && options == {} # If name is not set, use first parameter as the options hash
    options = name
    name = self.class.to_s
  end
  super
  set_remove_keys(options, %i[api_username default_hash template_name])
  @init_options = options
  @merged_options ||= init_merge_options # Caches initial merge options
end

Public Instance Methods

after_response(_response, _self) click to toggle source

Override this with 'after_response' within class definition to perform an action after response is retrieved @param [RestClient::Response] _response Response to interpret to perform after block

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 52
def after_response(_response, _self); end
calculated_json_path_matches(path, response, attribute, not_empty: false) click to toggle source

Calculate all JSON path values based on rules. ',', pascal_case @param [RestClient::Response] response Response from API @param [Object] path Xpath, JSONPath or other path identifying how to find element @param [String] attribute Generic attribute to find. Will override path @param [Boolean] not_empty Whether to fail if result is empty @return [Array] Paths to check as first and matching values (List of values matching JSON Path) as second

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 180
def calculated_json_path_matches(path, response, attribute, not_empty: false)
  path = add_pascal_path(path)
  paths_to_check = path.split(',')
  paths_to_check = paths_to_check.map { |path_to_check| prefix_json_path(path_to_check) }
  matching_values = paths_to_check.collect do |path_to_check|
    json_path_values_for(response, path_to_check, attribute: attribute)
  end.reject(&:empty?)
  raise NoElementAtPath, "No value at JSONPath '#{paths_to_check}' in '#{response.body}'" if matching_values.empty? && not_empty

  matching_values.first
end
found?(response) click to toggle source

@@return [Boolean] Whether the request found the desired value or not

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 126
def found?(response)
  status_code_for(response) != 404
end
hash_used_in_request(override_hash) click to toggle source

@param [Hash] override_hash Values to override default hash with @return [Hash] Hash used in REST request based on data conversion

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 75
def hash_used_in_request(override_hash)
  request = override_hash ? @default_hash.merge(override_hash) : @default_hash
  if pascal_keys?
    request.map { |k, v| [convert_to_pascal_case(k.to_s), v] }.to_h
  else
    request
  end
end
include_in_body?(response, expected) click to toggle source

@return [Boolean] Whether response body includes String

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 121
def include_in_body?(response, expected)
  response.body.include? expected
end
include_key?(response, expected) click to toggle source

@return [Boolean] Whether response body contains expected key

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 136
def include_key?(response, expected)
  value_from_path(response, expected)
  true
rescue NoElementAtPath
  false
end
include_value?(response, expected) click to toggle source

@return [Boolean] Whether response contains expected value

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 131
def include_value?(response, expected)
  extract_hash(response).include_value? expected
end
init_merge_options() click to toggle source

Initialize value of merged options Also called to verify any issues with options on creating object @return [Hash] Hash of merged options

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 105
def init_merge_options
  options = rest_resource_options
  options.merge! basic_auth_params if respond_to? :basic_auth_params
  options[:headers] ||= {}
  options[:headers].merge! parse_headers
  options[:headers][:authorization] ||= ERB.new('Bearer <%= access_token %>').result(binding) if Soaspec.auto_oauth && respond_to?(:access_token)
  options.merge(@init_options)
end
json_path_values_for(response, path, attribute: nil) click to toggle source

@return [Enumerable] List of values matching JSON path

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 168
def json_path_values_for(response, path, attribute: nil)
  raise 'JSON does not support attributes' if attribute

  JsonPath.on(response.body, path)
end
make_request(override_parameters) click to toggle source

Used in together with Exchange request that passes such override parameters @param [Hash] override_parameters Params to characterize REST request @option override_parameters [Hash] :params Extra parameters (E.g. headers) @option override_parameters [String] suburl URL appended to base_url of class @option override_parameters [Hash] :q Query for REST @option override_parameters [Symbol] :method REST method (:get, :post, :patch, etc) Following are for the body of the request @option override_parameters [Hash] :body Hash to be converted to JSON in request body @option override_parameters [String] :payload String to be passed directly in request body @option override_parameters [String] :template_name Path to file to be read via ERB and passed in request body @return [RestClient::Response] Response from making request

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 65
def make_request(override_parameters)
  req_params = request_parameters override_parameters
  response = req_params.call @merged_options
  Soaspec::SpecLogger.info("response:\n  headers: #{response&.headers}\n  body: #{response}\n")
  after_response(response, self)
  response
end
parse_headers() click to toggle source

Perform ERB on each header value @return [Hash] Hash from 'rest_client_headers' passed through ERB

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 94
def parse_headers
  Hash[rest_client_headers.map do |header_name, header_value|
    raise ArgumentError, "Header '#{header_name}' is null. Headers are #{rest_client_headers}" if header_value.nil?

    [header_name, ERB.new(header_value).result(binding)]
  end]
end
request(response) click to toggle source

@return [RestClient::Request, String] Request of API call. Either intended request or actual request

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 233
def request(response)
  if response.nil?
    return 'Request not yet sent. Call :request_parameters' \
    'for what will be sent'
  end

  response.request
end
request_parameters(override_parameters) click to toggle source

@return [Soaspec::RestRequest] Parameters used in making a request

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 45
def request_parameters(override_parameters)
  RestRequest.new(override_parameters, @merged_options, self)
end
response_body(response, format: :hash) click to toggle source

@param [Hash] format Format of expected result. @return [Object] Generic body to be displayed in error messages

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 116
def response_body(response, format: :hash)
  extract_hash response
end
rest_resource_options() click to toggle source

Add values to here when extending this class to have default REST options. See rest client resource at github.com/rest-client/rest-client for details It's easier to set headers via 'headers' accessor rather than here @return [Hash] Options adding to & overriding defaults

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 88
def rest_resource_options
  {}
end
status_code_for(response) click to toggle source

@return [Integer] HTTP Status code for response

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 144
def status_code_for(response)
  response&.code
end
value_from_path(response, path, attribute: nil) click to toggle source

Based on a exchange, return the value at the provided xpath If the path does not begin with a '/', a '//' is added to it @param [RestClient::Response] response Response from API @param [Object] path Xpath, JSONPath or other path identifying how to find element @param [String] attribute Generic attribute to find. Will override path @return [String] Value at Xpath

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 198
def value_from_path(response, path, attribute: nil)
  path = path.to_s
  case Interpreter.response_type_for(response)
  when :xml, :html
    result = xpath_elements_for(response: response, xpath: path, attribute: attribute).first
    raise NoElementAtPath, "No value at Xpath '#{prefix_xpath(path, attribute)}' in '#{response.body}'" unless result
    return result.inner_text if attribute.nil?

    result.attributes[attribute].inner_text
  when :json
    matching_values = calculated_json_path_matches(path, response, attribute, not_empty: true)
    matching_values.first
  else # Assume this is a String
    raise NoElementAtPath, 'Response is empty' if response.to_s.empty?

    response.to_s[/#{path}/] # Perform regular expression using path if not XML nor JSON
  end
end
values_from_path(response, path, attribute: nil) click to toggle source

@return [Enumerable] List of values returned from path

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 218
def values_from_path(response, path, attribute: nil)
  path = path.to_s
  case Interpreter.response_type_for(response)
  when :xml
    xpath_elements_for(response: response, xpath: path, attribute: attribute).map(&:inner_text)
  when :json
    result = calculated_json_path_matches(path, response, attribute)
    result || []
    # json_path_values_for(response, path, attribute: attribute)
  else
    raise "Unable to interpret type of #{response.body}"
  end
end
xpath_elements_for(response: nil, xpath: nil, attribute: nil) click to toggle source

Returns the value at the provided xpath @param [RestClient::Response] response @param [String] xpath Path to find elements from @param [String] attribute Attribute to find path for @return [Enumerable] Value inside element found through Xpath

# File lib/soaspec/exchange_handlers/rest_handler.rb, line 153
def xpath_elements_for(response: nil, xpath: nil, attribute: nil)
  raise ArgumentError unless response && xpath
  raise "Can't perform XPATH if response is not XML" unless %i[xml html].include? Interpreter.response_type_for(response)

  xpath = prefix_xpath(xpath, attribute)
  temp_doc = Nokogiri.parse(response.body).dup
  if strip_namespaces? && !xpath.include?(':')
    temp_doc.remove_namespaces!
    temp_doc.xpath(xpath)
  else
    temp_doc.xpath(xpath, temp_doc.collect_namespaces)
  end
end