Request doesn't pass parameters in the right order
I'm calling a SOAP service with Savon 2.5.1 like this:
client.call(:operation_name, message: { 'request' => some_hash })
The generated request contains the keys and values from some_hash in the order in which they appear in the hash, rather than the order specified by the WSDL schema. Therefore, depending on the ordering of the hash, the request may or may not be valid.
Savon should refuse to send non-schema-conforming requests. At a minimum, it should raise an error in such a case, but it would be even better if it could reorder the elements based on the order specified in the schema.
Thanks for opening this issue @afn -- I wasn't aware of this issue. Based on my understanding of how Savon constructs xml from the given hash, this seems a tad difficult to solve. Savon uses Gyoku which does support ordering.
It seems to solve this, Savon would need to understand the correct order from the schema and provide that order to Gyoku.
I couldn't find any great examples of this online -- it seems that the order should be specified via the parameterOrder attribute on parameters inside of an operation? Does that sound correct?
@tjarratt I'm not familiar with parameterOrder, but I think that's unrelated. In our case, the problem is that the XML schema has a <sequence> (which implies an ordering) but Savon is ignoring that order. Here's an example:
client = Savon.client(wsdl: 'http://www.webservicex.net/CurrencyConvertor.asmx?WSDL', log_level: :debug, log: true)
client.call(:conversion_rate, message: {'ToCurrency' => 'USD', 'FromCurrency' => 'CAD'})
# => <?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.webserviceX.NET/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><tns:ConversionRate><tns:ToCurrency>USD</tns:ToCurrency><tns:FromCurrency>CAD</tns:FromCurrency></tns:ConversionRate></env:Body></env:Envelope>
Note how the request has <ToCurrency> before <FromCurrency> even though the WSDL file has:
<s:element name="ConversionRate">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="FromCurrency" type="tns:Currency"/>
<s:element minOccurs="1" maxOccurs="1" name="ToCurrency" type="tns:Currency"/>
</s:sequence>
</s:complexType>
</s:element>
This request technically violates the schema, although this particular server is forgiving of the error and works anyway. Unfortunately, not all servers are as forgiving; one of the web services we've integrated with actually silently ignores elements that are out of order.
Thanks again! Tony
It seems rather straightforward to support the
Sent From A Very Small Keyboard
On Jul 2, 2014, at 10:29, Tony Novak [email protected] wrote:
@tjarratt I'm not familiar with parameterOrder, but I think that's unrelated. In our case, the problem is that the XML schema has a
(which implies an ordering) but Savon is ignoring that order. Here's an example: client = Savon.client(wsdl: 'http://www.webservicex.net/CurrencyConvertor.asmx?WSDL', log_level: :debug, log: true) client.call(:conversion_rate, message: {'ToCurrency' => 'USD', 'FromCurrency' => 'CAD'})
=> <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.webserviceX.NET/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">env:Bodytns:ConversionRatetns:ToCurrencyUSD/tns:ToCurrencytns:FromCurrencyCAD/tns:FromCurrency/tns:ConversionRate/env:Body/env:Envelope
Note how the request has <ToCurrency> before <FromCurrency> even though the WSDL file has:
<s:element name="ConversionRate"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="FromCurrency" type="tns:Currency"/> <s:element minOccurs="1" maxOccurs="1" name="ToCurrency" type="tns:Currency"/> /s:sequence /s:complexType /s:element This request technically violates the schema, although this particular server is forgiving of the error and works anyway. Unfortunately, not all servers are as forgiving; one of the web services we've integrated with actually silently ignores elements that are out of order.
Thanks again! Tony
— Reply to this email directly or view it on GitHub.
I have the same issue with WS-Security. The web service requires the Timestamp before the UsernameToken but Savon always puts Timestamp last so I get 'action mismatch' error from the server. Is there a way to order the elements in the WS-Security header?
@codebrane I'm afraid that there isn't some easy, obvious answer to this. It's necessary to do the hard work in Savon to make this work, and unfortunately I don't have a lot of time to investigate this more. Even if I did, I don't have access to a SOAP server that would allow me to verify that any changes to Savon would work.
I'm more than happy to merge any pull requests for this behavior, or to answer questions any potential contributor might have, but I can't recommend any quick fixes today.
I encountered the same issue and monkey patched savon so it will always put the (top-level) keys in a SOAP request in the same order they were defined in the WSDL request. This may serve as a quick fix.
# Monkey patch savon to automatically put message keys
# in the order defined in the WSDL.
class Savon::Builder
alias :message_without_order :message
def message
params = @wsdl.operations[@operation_name][:parameters].keys
message = @locals[:message]
ordered_message = {}
params.each do |param_name|
ordered_message[param_name.to_s] = message[param_name.to_s]
end
@locals[:message] = ordered_message
message_without_order
end
end
Hi there, I think we just ran into this issue :)
So I just wanted to check, if this issue is still unresolved?
@tjarratt suggested that a solution using the sequence tag should be straight-forward so I suppose my question is: Has that solution been implemented somewhere?
@janraasch you'd probably need to look at all of the forks of Savon to see if anyone implemented it. I can't think of any PRs for it, but I'm not sure that I would remember one, even if I had merged it myself.
I just submitted a pull request (#802) that fixes the element sequencing issue and also fixes a namespace issue when dealing with array schema elements.
I updated the pull request to play nicer with existing Savon features, and to use Gyoku to correctly order the elements.
In order to activate the automatic ordering based on the XML schema, you need to include an :order! key with a value of :use_schema in the top-level parameter hash
I think we duplicated this ticket in #859
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
It would be great to get some kind of solution for this merged into Savon. The pull request that I submitted has fixed the issue for us. Do we want something different?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I need to update the pull request when I get some time.
I'm having the same problem, How can iI fix it to keep the order?
The pull request provides a way to keep the ordering, but it needs to be updated.
reopening with an updated commit off of main branch. can someone verify if this commit addresses their issue?:
https://github.com/savonrb/savon/commit/7351ccd1d94f29a65c4e7de7bf60c06d189922a8