WSDL Operations not being updated - ruby

I'm a bit stumped as to why our new operations are not being picked up when using the Savon gem but are when using a simple curl command.
For example when using Savon
#client = Savon.client(wsdl: "#url-here", basic_auth: %w(username password))
#client.operations
:operation_name
# At this point i expect the operation to be OperationName
When I then run a curl request
curl #url-here --user username:password
Within the XML response is
<operation name="OperationName">
We recently changed the naming convention of our operations to camel case (previously using snake case) so the tests used to pass but now they fail as not picking up the new operations (When using Savon)
Would there be any reason for this ?
Thanks

Since version 1 of Savon:
Your service probably uses (lower)CamelCase names for actions and params, but Savon maps those to snake_case Symbols for you.
I assume, Savon mapped your new camel case actions to snake case. So if you had updated your tests - you shouldn't.

Related

How to perform a savon client.call use a GET request with a payload instead of a POST?

I'm using savonrb (2.1.2) to perform my SOAP requests against a Web Service.
The problem I came into is that it looks like I do not have any chance to perform an HTTP GET request instead of a POST request using this library.
Please, note that even though I can agree with the fact that a SOAP over HTTP done through a GET method, instead that through a POST, might look unconventional or even an error, but
I cannot modify the server side, and, as client, I MUST accept this behavior as a matter of fact.
How can I overcome this problem?
Standing to what I've seen so far inside the code of savon, it looks like it is an immutable design decision:
# operation.rb
module Savon
class Operation
...
def call_with_logging(request)
#logger.log(request) { HTTPI.post(request, #globals[:adapter]) }
end
...
end
end
I just wonder if there should be a trick, through the mechanism of the savon adapters, to avoid this kind of (bad) solution.

How to generate the following XML using Savon

I have been trying to know how to build a SOAP XML request having different tags with different namespaces through Savon - as that shown below - but haven't been able to do it yet. Could anybody please help me? The request written below was generated by SOAPUI (linked it a WSDL). Notice the urn and urn1 prefixes for namespaces. I use Savon 2, Ruby 1.9 and Rails 3.
<soapenv:Envelope xmlns:urn="urn:safetypay:messages:mws:api" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn1="urn:safetypay:schema:mws:api">
<soapenv:Body>
<urn:ExpressTokenRequest>
<urn1:Language>ES</urn1:Language>
<urn:Signature>2984764ac8214cca0a44e06badaba4bbc93ed381af59199f65d9c</urn:Signature>
</urn:ExpressTokenRequest>
</soapenv:Body>
</soapenv:Envelope>
Thank you in advance :)
I WANT TO SHARE THE SOLUTION:
Finally, I was able to puzzle it out. Notice that the code posted in this forum is not exactly the real one for security and/or brevity purposes (it's incomplete).
# Instance of the Savon client using the respective wsdl. Notice the two (multiple) namespaces.
# Also, see the namespace prefix urn (making it different to the default one).
# In addition,the code changed the envelope namespace prefix to soapenv.
# While debugging in console (irb), I used the parameters log: true, pretty_print_xml: true inside the following client instance too (e.g. ...env_namespace: :soapenv, log: true, pretty_print_xml: true... ). This allowed me to see very easily the XML Savon was sending when requesting.
# Remember to require the necessary resources. Maybe require 'savon', require 'digest',...
client = Savon.client(wsdl: "/MerchantExpressWs.wsdl", namespaces: {"xmlns:urn" => "urn:safetypay:messages:mws:api", "xmlns:urn1" =>"urn:safetypay:schema:mws:api"}, namespace_identifier: :urn, env_namespace: :soapenv)
# Assignment of variables below must be done in this case. I don't write it here to be this code not so large.
# A thing I lasted much time to know how to do was to add the prefix urn1 only to the tag Language (urn1:Language), since the code was adding urn to all due to the namespace_identifier: :urn (see the client instance above). As you can see, I simply added it to the array message (message1).
message1 = {"urn1:Language" => language, "Signature"=> signature }
# The respective operation for this request is create_express_token.
response = client.call(:create_express_token, message: message1 )
# This was the way Savon sent the request as needed by the Web Service. Savon added additional namespaces in comparison to the original XML request I wanted to send, but it was not problematic, it was OK (e.g., it added some additional stuff to the namespaces soapenv, urn, urn1)
I hope this post helps many to make easy to consume SOAP Web Services through Savon - Ruby (and maybe with Rails).
Thank God primarily for every good thing :)

RestClient using Resource for GET action

I am writing a ruby client for the REST API using RestClient gem. While going through examples, I see different code used to achieve basically the same result, without any explanation on the difference.
client = RestClient::Resource.new('https://example.com/')
response = client.get
VS
response = RestClient.get('https://example.com/')
What is the benefit of using Resource class, if I can achieve same thing with get method?
Code reuse. It's especially useful when you're dealing with APIs, and you need to hit the same base urls over and over, with different params and/or paths. As the docs show you, once you build a base resource:
client = RestClient::Resource.new('https://example.com/')
You can access other paths under this resource quite easily:
response = client["/users/1"].get
Which is equivalent to
response = RestClient.get("https://example.com/users/1")
but less typing/repetition.

Savon v3.x - how to pass complete xml message as soap request

using Savon version 3.x (the current master branch found https://github.com/savonrb/savon).
currently to generate a soap request in savon 3 you define the body of the message as a hash, ex:
operation.body = {
Search: {
accountID: 23,
accountStatus: 'closed'
}
}
response = operation.call
from the hash, savon will generate the complete soap message xml (envelope, headers, etc..) and pass that message onto HttpClient to post the request to your soap endpoint.
instead of a hash, i'd like to be able to pass in a complete xml message as my request, ex:
my_xml_request_message ='
..... lots more nested nodes, namespaces and tons of attributes, etc .....
'
it appears that body is sent to build to create the soap request, and is then posted by call:
https://github.com/savonrb/savon/blob/master/lib/savon/operation.rb#L79
def call
raw_response = #http.post(endpoint, http_headers, build)
Response.new(raw_response)
end
so i thinking was to monkey patch? call to allow me to override build with my xml block, ex:
def call
raw_response = #http.post(endpoint, http_headers, my_xml_request_message)
Response.new(raw_response)
end
that's where we're getting stuck - it's not clear to me if my xml is getting created or posted correctly. or if this is the correct way to proceed...
thanks in advance for any help!
I don't use Savon3 yet, because it's not stable yet. What you can do in v2 is:
client.call(:authenticate, xml: "<envelope><body></body></envelope>")
I suppose something similar will work in v3 as well. It existed in v1 and v2.
monkey patch solved our problem - so i think this is good answer for now.
we're looking to add this solution to savon 3 master if possible, details: https://github.com/savonrb/savon/issues/546
class Savon
class Operation
attr_accessor :raw_xml_envelope
def call
message = (raw_xml_envelope != nil ? raw_xml_envelope : build)
raw_response = #http.post(endpoint, http_headers, message)
Response.new(raw_response)
end
end
end
more background:
we've built a webservices (SOAP & REST) testing framework using Savon for the soap backbone. in our framework we define a couple methods describing each wsdl operation, our use case is to allow usage of the savon body() method when wanting to define the xml body as a hash (as described by savon's example_body()) or to pass in the complete raw xml envelope - which we are able to do using raw_xml_envelope() method above via monkey patch.

Typeerror when parsing JSON from API

I'm implementing a simple tumblr api tool for my girlfriend, and I'm having some trouble working with the data handed to me by Tumblr.
The structure handed back can be found here (scroll down a little for the example.)
The following string of hash keys works while I'm working manually in IRB:
followers_result['response']['users']
But when I launch the server and try to walk the json hash, I get a "Can't convert string to integer" typeerror. Using the following code, response['users'] is identified as the problem field. (I expanded the hashtree query a bit here.)
followers_result = JSON.parse(#followers_response.body)
response = followers_result['response']
users = response['users']
users.each do |follower|
followers << follower['name']
end
I'm having the same problem with my other request, which requires a few more nodes down the tree... Anyone know why this would be different between server and irb?
(One difference is that the server is requesting via OAuth whereas my irb tests are requesting via net/http, but I'm taking the exact same OAuth query and adding my API key on to do the tests with. I'm not sure how to manually request it via OAuth to make sure that the server is getting the same document because of the three-legged authentication.)
Thanks for any help/suggestions,
Cameron

Resources