lib/stockboy/providers/soap.rb
require 'stockboy/provider'
require 'stockboy/string_pool'
require 'savon'
module Stockboy::Providers
# Fetch data from a SOAP endpoint
#
# Backed by Savon gem, see savon for full configuration options: extra
# options are passed through.
#
class SOAP < Stockboy::Provider
include Stockboy::StringPool
# @!group Options
#
# These options correspond to Savon client options
# URL with the WSDL document
#
# @!attribute [rw] wsdl
# @return [String]
# @example
# wsdl "http://example.com/api/soap?wsdl"
#
dsl_attr :wsdl
# Maximum time to establish a connection
#
# @!attribute [rw] open_timeout
# @return [Integer]
# @example
# open_timeout 10
#
dsl_attr :open_timeout
# Maximum time to read data from connection
#
# @!attribute [rw] read_timeout
# @return [Integer]
# @example
# read_timeout 10
#
dsl_attr :read_timeout
# The name of the request, see your SOAP documentation
#
# @!attribute [rw] request
# @return [String]
# @example
# request "allItemsDetails"
#
dsl_attr :request
# @return [Symbol]
# @example
# env_namespace :soapenv
#
dsl_attr :env_namespace
# @return [String]
# @!attribute [rw] namespace
# Optional if specified in WSDL
#
dsl_attr :namespace
# @return [Hash]
# @!attribute [rw] namespaces
# Optional if specified in WSDL
#
dsl_attr :namespaces
# @return [String]
# @!attribute [rw] namespace_id
# Optional if specified in WSDL
#
dsl_attr :namespace_id
# @return [String]
# @!attribute [rw] endpoint
# Optional if specified in WSDL
#
dsl_attr :endpoint
# Hash of message options passed in the request, often includes
# credentials and query options.
#
# @!attribute [rw] message
# @return [Hash]
# @example
# message "clientId" => "12345", "updatedSince" => "2012-12-12"
#
dsl_attr :message
# Message tag name
#
# @!attribute [rw] message_tag
# @return [String]
# @example
# message_tag "GetResult"
#
dsl_attr :message_tag
# @return [String]
# @example
# soap_action "urn:processMessage"
#
dsl_attr :soap_action
# XML string to override the Soap headers
#
# @!attribute [rw] soap_header
# @return [String]
# @example
# soap_header "<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">..."
#
dsl_attr :soap_header
# @return [Hash]
# @example
# attributes {}
#
dsl_attr :attributes
# Change the default response type, default :hash
#
# @!attribute [rw] response_format
# @return [Symbol]
# @example
# response_format :xml
#
dsl_attr :response_format
# Hash of optional HTTP request headers
#
# @!attribute [rw] headers
# @return [Hash]
# @example
# headers "X-ClientKey" => "12345"
#
dsl_attr :headers
# Array of WSSE Auth values
#
# @!attribute [rw] wsse_auth
# @return [Array]
# @example
# wsse_auth ["Username", "Password"]
#
dsl_attr :wsse_auth
# @!endgroup
# Initialize a new SOAP provider
#
def initialize(opts={}, &block)
super
@response_format = opts[:response_format] || :hash
DSL.new(self).instance_eval(&block) if block_given?
end
# Connection object to the configured SOAP endpoint
#
# @return [Savon::Client]
#
def client
@client ||= Savon.client(client_options)
@client.globals.open_timeout(open_timeout) if open_timeout
@client.globals.read_timeout(read_timeout) if read_timeout
yield @client if block_given?
@client
end
private
def client_options
opts = if wsdl
{wsdl: wsdl}
elsif endpoint
{endpoint: endpoint}
end
opts[:open_timeout] = open_timeout if open_timeout
opts[:read_timeout] = read_timeout if read_timeout
opts[:logger] = logger
opts[:log] = logger.debug?
opts[:convert_response_tags_to] = ->(tag) { string_pool(tag) }
opts[:namespace] = namespace if namespace
opts[:namespaces] = namespaces if namespaces
opts[:namespace_identifier] = namespace_id if namespace_id
opts[:env_namespace] = env_namespace if env_namespace
opts[:headers] = headers if headers
opts[:wsse_auth] = wsse_auth if wsse_auth
opts
end
def validate
errors << "endpoint or wsdl must be specified" if endpoint.blank? unless wsdl
errors.blank?
end
def fetch_data
with_string_pool do
response = client.call(
@request,
message: message,
message_tag: message_tag,
soap_action: soap_action,
soap_header: soap_header,
attributes: attributes
)
@data = case response_format
when :xml
response.xml
else
response.body
end
end
end
end
end