Class: Savon::Operation

Inherits:
Object
  • Object
show all
Defined in:
lib/savon/operation.rb

Overview

Represents a single named SOAP operation.

Bridges the SOAP layer (envelope building, action headers, multipart) and the transport layer (execution, logging). Knows nothing about transport internals such as proxy, SSL, or auth.

Constant Summary collapse

CONTENT_TYPE =

SOAP Content-Type values indexed by SOAP version. SOAP 1.1 §6 (HTTP binding), SOAP 1.2 Part 2 §7.1.4 (HTTP media type)

{
  1 => "text/xml;charset=%s",
  2 => "application/soap+xml;charset=%s"
}.freeze
SOAP_REQUEST_TYPE =

Maps SOAP version to the base MIME type used in multipart requests. RFC 2387 §3.1 (multipart/related Content-Type parameter)

{
  1 => "text/xml",
  2 => "application/soap+xml"
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, wsdl, globals, transport) ⇒ Operation

Returns a new instance of Operation.



60
61
62
63
64
65
# File 'lib/savon/operation.rb', line 60

def initialize(name, wsdl, globals, transport)
  @name      = name
  @wsdl      = wsdl
  @globals   = globals
  @transport = transport
end

Class Method Details

.create(operation_name, wsdl, globals, transport) ⇒ Object



34
35
36
37
38
39
40
41
# File 'lib/savon/operation.rb', line 34

def self.create(operation_name, wsdl, globals, transport)
  if wsdl.document?
    ensure_name_is_symbol! operation_name
    ensure_exists! operation_name, wsdl, transport
  end

  new(operation_name, wsdl, globals, transport)
end

.ensure_exists!(operation_name, wsdl, transport) ⇒ Object

Verifies the operation is provided by the WSDL.



44
45
46
47
48
49
50
51
# File 'lib/savon/operation.rb', line 44

def self.ensure_exists!(operation_name, wsdl, transport)
  unless wsdl.soap_actions.include? operation_name
    raise UnknownOperationError, "Unable to find SOAP operation: #{operation_name.inspect}\n" \
                                 "Operations provided by your service: #{wsdl.soap_actions.inspect}"
  end
rescue Wasabi::Resolver::HTTPError => e
  raise HTTPError, transport.normalize_response(e.response)
end

.ensure_name_is_symbol!(operation_name) ⇒ Object

Raises:

  • (ArgumentError)


53
54
55
56
57
58
# File 'lib/savon/operation.rb', line 53

def self.ensure_name_is_symbol!(operation_name)
  return if operation_name.is_a? Symbol

  raise ArgumentError, "Expected the first parameter (the name of the operation to call) to be a symbol\n" \
                       "Actual: #{operation_name.inspect} (#{operation_name.class})"
end

Instance Method Details

#build(locals = {}, &block) ⇒ Object



67
68
69
70
# File 'lib/savon/operation.rb', line 67

def build(locals = {}, &block)
  set_locals(locals, block)
  Builder.new(@name, @wsdl, @globals, @locals)
end

#call(locals = {}, &block) ⇒ Object

Executes the SOAP operation and returns a Savon::Response.

Observer short-circuit: if any registered observer returns a Transport::Response (or legacy HTTPI::Response), the HTTP call is skipped and that response is used directly.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/savon/operation.rb', line 77

def call(locals = {}, &block)
  builder = build(locals, &block)
  observer_response = Savon.notify_observers(@name, builder, @globals, @locals)

  transport_response =
    if observer_response.nil?
      body = builder.to_s
      headers = soap_headers(builder)
      @transport.post(endpoint.to_s, headers, body, @locals)
    else
      normalize_observer_response(observer_response)
    end

  Response.new(transport_response, @globals, @locals)
end

#request(locals = {}, &block) ⇒ Object

Builds and returns the HTTPI::Request that would be sent for this operation, without executing it. Useful for inspection and debugging. Not supported with transport: :faraday.



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/savon/operation.rb', line 96

def request(locals = {}, &block)
  if @globals[:transport] == :faraday
    raise ArgumentError, "#request returns an HTTPI::Request and is not supported " \
                         "with transport: :faraday. Use client.faraday to configure " \
                         "the connection"
  end

  builder = build(locals, &block)
  # Build the body before soap_headers - see #call.
  body = builder.to_s
  @transport.to_httpi_request(endpoint.to_s, soap_headers(builder), body, @locals)
end