Skip to content

Commit

Permalink
rewrite in progess
Browse files Browse the repository at this point in the history
  • Loading branch information
rubiii committed Nov 12, 2009
1 parent 1716e72 commit 8540ebd
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 156 deletions.
81 changes: 46 additions & 35 deletions README.rdoc
Original file line number Diff line number Diff line change
@@ -1,60 +1,71 @@
= Savon
h1. Savon

Savon::Service is a SOAP client library to enjoy. The goal is to minimize
the overhead of working with SOAP services and provide a lightweight
alternative to other libraries.
p. Savon can be installed as a gem from the "gemcutter":http://gemcutter.org repository.
Please follow the steps on their website to set up your rubygems installation.

== Install
bc. $ gem install savon

The gem for Savon is in the {gemcutter}[http://gemcutter.org] repository.
Please follow the steps on their website to set up your rubygems installation.
Afterwards you can install the gem like this:
h3. Dependencies

bc. cobravsmongoose = 0.0.2
hpricot 0.8.2 (JRuby-compatible version)

h2. Getting started

p. Instantiate a new instance of Savon::Service, passing in the WSDL of your service.

bc. proxy = Savon::Service.new 'http://example.com/UserService?wsdl'

$ gem install savon
h3. The WSDL

== Dependencies
p. Use the WSDL object to find out about the SOAP actions offered by the service.

cobravsmongoose = 0.0.2
hpricot 0.8.2 (JRuby-compatible version)
bc. proxy.wsdl.soap_actions
=> ["getAllUsers", "getUserById"]

== How to use
p. Find out more about the [[WSDL]] object.

Instantiate a new Savon::Service instance passing in the WSDL of your service.
h3. Calling a SOAP action

proxy = Savon::Service.new("http://example.com/ExampleService?wsdl")
p. Now without any setup (assuming your service applies to the default [[Options]]),
you can just call any available SOAP action.

Call the SOAP service method of your choice on your Savon::Service instance.
bc. response = proxy.getAllUsers

response = proxy.get_all_users
p. In case your SOAP actions are named in lowerCamelCase or CamelCase you can also
call them using snake_case, which feels much more natural.

Or pass in a Hash of options for the SOAP service to receive.
bc. response = proxy.get_all_users

response = proxy.find_user_by_id(:id => 123)
h3. Parameters

Or specify a custom XPath-Expression to start translating the SOAP response at.
By default the response is translated starting at "//return".
p. Specifying parameters to be received by the SOAP service, can be done by passing
a Hash to the SOAP action call.

response = proxy.find_user_by_id(nil, "//user/email")
bc. response = proxy.get_user_by_id 'id' => { '$' => "666" }

=== Check for available SOAP actions
p. Like to learn more about Parameters? Then take a look at: [[BadgerFish]].

Access the WSDL to get an Array of SOAP actions found in the WSDL document.
h3. The response

proxy.wsdl.soap_actions
# => [ "getAllUsers", "findUserById" ]
p. The SOAP (XML) response is translated into a Hash following the [[BadgerFish]]
convention. By default (see [[Options]]) translation starts at the '//return' (XPath
expression) node of the XML response.

=== Handle HTTP error and SOAP faults
bc. p proxy.get_user_by_id 'id' => { '$' => "666" }
=> { 'user' => { '@id' => '666', '@username' => 'dude', '$' => 'biography' } }

Savon::Service raises a Savon::SOAPFault in case of a SOAP fault and a
Savon::HTTPError in case of an HTTP error.
h3. HTTP errors and SOAP faults

=== Logging request and response
p. Savon raises a Savon::SOAPFault in case of a SOAP fault and a Savon::HTTPError
in case of an HTTP error. More information about [[Errors]].

You should specify the logger to use before working with any service.
h3. Logging

# example for Ruby on Rails
Savon.logger = RAILS_DEFAULT_LOGGER
p. Savon logs each request and response, but you need to specify the logger and
log level to use.

Of course you can also specify the log level if needed. By default it's set to :debug.
bc. Savon.logger = Logger.new STDOUT
Savon.log_level = :info

Savon.log_level = :info
Read more about [[Logging]].
2 changes: 1 addition & 1 deletion lib/savon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ def self.log(message = nil)

end

%w(service options http wsdl request).each do |file|
%w(service options http wsdl request inflector).each do |file|
require File.join(File.dirname(__FILE__), "savon", file)
end
78 changes: 12 additions & 66 deletions lib/savon/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,40 +22,11 @@ def retrieve_wsdl
def request(soap_action, soap_body)
request = Request.new soap_action, soap_body, @namespace_uri, @options

p "------------------------------------------------"
p request.body
p "------------------------------------------------"

log_request request.headers, request.body
@response = http.request_post @options.endpoint.path, request.body, request.headers
@response.body



log_response


=begin
ApricotEatsGorilla.nodes_to_namespace = { :wsdl => wsdl.choice_elements }
headers, body = build_request_parameters(soap_action, soap_body)
Savon.log("SOAP request: #{@endpoint}")
Savon.log(headers.map { |k, v| "#{k}: #{v}" }.join(", "))
Savon.log(body)
response = http.request_post(@endpoint.path, body, headers)
Savon.log("SOAP response (status #{response.code}):")
Savon.log(response.body)
soap_fault = ApricotEatsGorilla[response.body, "//soap:Fault"]
raise_soap_fault(soap_fault) if soap_fault && !soap_fault.empty?
raise_http_error(response) if response.code.to_i >= 300
if pure_response?
response.body
else
ApricotEatsGorilla[response.body, response_xpath]
end
=end
@response
end

# Returns the WSDL endpoint.
Expand All @@ -69,43 +40,18 @@ def http
@http ||= Net::HTTP.new @options.endpoint.host, @options.endpoint.port
end

def log_request(headers, body)
Savon.log "SOAP request: #{@endpoint}"
Savon.log headers.map { |k, v| "#{k}: #{v}" }.join(', ')
Savon.log body
end



=begin
namespaces = {} unless namespaces.kind_of? Hash
if namespaces["xmlns:env"].nil? && SOAPNamespace[version]
namespaces["xmlns:env"] = SOAPNamespace[version]
end
header = xml_node("env:Header") { wsse_soap_header(wsse) }
body = xml_node("env:Body") { (yield if block_given?) || nil }
xml_node("env:Envelope", namespaces) { header + body }
<env:Envelope xmlns:wsdl="http://v1_0.ws.inforeason.marge.blau.de/"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header />
<env:Body>
<wsdl:getAllInfoReasons></wsdl:getAllInfoReasons>
</env:Body>
</env:Envelope>
=end
def log_response
Savon.log "SOAP response (status #{@response.code}):"
Savon.log @response.body
end

=begin
# Expects the requested +soap_action+ and +soap_body+ and builds and
# returns the request header and body to dispatch a SOAP request.
def build_request_parameters(soap_action, soap_body)
headers = { "Content-Type" => ContentType[@version], "SOAPAction" => soap_action }
namespaces = { "xmlns:wsdl" => wsdl.namespace_uri }
body = ApricotEatsGorilla.soap_envelope(namespaces, wsse, @version) do
ApricotEatsGorilla["wsdl:#{soap_action}" => soap_body]
end
[headers, body]
end
# Returns the WSSE arguments if :wsse_username and :wsse_password are set.
def wsse
Expand Down
34 changes: 24 additions & 10 deletions lib/savon/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,35 @@ class Options
}

# The default SOAP version.
@@default_soap_version = 1
@@soap_version = 1

# Sets the default SOAP version to use.
def self.default_soap_version=(soap_version)
@@default_soap_version = soap_version
def self.soap_version=(soap_version)
@@soap_version = soap_version
end

# The default XML root node.
@@default_root_node = '//return'
# The default response processing.
@@process_response = lambda do |response|
doc = Hpricot.XML response.body
nodes = doc.search '//return'

if nodes.size > 1
nodes.map { |node| CobraVsMongoose.xml_to_hash node }
else
CobraVsMongoose.xml_to_hash nodes
end
end

# Sets the default XML root node.
def self.default_root_node=(root_node)
@@default_root_node = root_node
# Returns a Proc object to process the response.
def process_response
@process_response || @@process_response
end

# Sets the Proc object to process the response.
def process_response=(process_response)
@process_response if process_response.respond_to? :call
end

# Returns the endpoint.
attr_reader :endpoint

Expand All @@ -39,7 +53,7 @@ def endpoint=(endpoint)

# Returns the SOAP version. Defaults to +@@default_soap_version+.
def soap_version
@soap_version || @@default_soap_version
@soap_version || @@soap_version
end

# Sets the SOAP version to the given +soap_version+.
Expand All @@ -50,7 +64,7 @@ def soap_version=(soap_version)

# Returns the XML root node. Defaults to +@@default_root_node+.
def root_node
@root_node || @@default_root_node
@root_node || @@root_node
end

# Sets the XML root node to the given +root_node+.
Expand Down
9 changes: 6 additions & 3 deletions lib/savon/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Savon
class Request

# Content-Types by SOAP version.
ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
ContentType = { 1 => 'text/xml', 2 => 'application/soap+xml' }

def initialize(soap_action, soap_body, namespace_uri, options)
@soap_action = soap_action
Expand All @@ -12,7 +12,10 @@ def initialize(soap_action, soap_body, namespace_uri, options)
end

def headers
{ 'Content-Type' => ContentType[@options.soap_version], 'SOAPAction' => @soap_action }
@headers ||= {
'Content-Type' => ContentType[@options.soap_version],
'SOAPAction' => @soap_action
}
end

def body
Expand All @@ -37,7 +40,7 @@ def envelope_namespaces
def envelope_header
header = { 'env:Header' => { '$' => '%s' } }
header = CobraVsMongoose.hash_to_xml header
header % "" #TODO: add wsse support
header % '' #TODO: add wsse support
end

def envelope_body
Expand Down
Loading

0 comments on commit 8540ebd

Please sign in to comment.