I am trying to hit a SOAP Service from Ruby on Rails - from SOAP UI I can hit it fine and the request XML is as below:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:mun="http://schemas.datacontract.org/2004/07/MyExternalService.Map" xmlns:mun1="http://schemas.datacontract.org/2004/07/MyExternalService.Common.Map">
<soapenv:Header/>
<soapenv:Body>
<tem:GetInformationsForCoordinates>
<!--Optional:-->
<tem:coordReq>
<!--Optional:-->
<mun:Coordinates>
<!--Zero or more repetitions:-->
<mun:Coordinate>
<!--Optional:-->
<mun:Id>1</mun:Id>
<!--Optional:-->
<mun:QualityIndex>90</mun:QualityIndex>
<!--Optional:-->
<mun:X>-110.5322</mun:X>
<!--Optional:-->
<mun:Y>35.2108</mun:Y>
</mun:Coordinate>
</mun:Coordinates>
</tem:coordReq>
<!--Optional:-->
<tem:analysisTypes>
<!--Zero or more repetitions:-->
<mun:AnalysisType>Additional</mun:AnalysisType>
</tem:analysisTypes>
</tem:GetInformationsForCoordinates>
</soapenv:Body>
</soapenv:Envelope>
If I copy that exact XML into a Ruby string with request = %q(XML STRING) into savon and use the method and then in Savon call the following:
response = client.call(:get_info, xml: request)
It works as expected and I get my response - however in reality I want to be just passing the parameters to Savon. So far I have tried the following:
coordinate = { Id: '1', X: -110.5322, Y: 35.2108, QualityIndex: 90 }
coordinates = {Coordinates: [coordinate] }
coordinateReq = {coordReq: {coordinates: coordinates} }
response = client.call(:get_informations_for_coordinates, message: coordinateReq)
This fails and if I look at the XML I am sending it is below:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://tempuri.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<tns:GetInformationsForCoordinates>
<coordReq>
<coordinates>
<coordinates>
<Id>1</Id>
<X>-110.5322</X>
<Y>35.2108</Y>
<QualityIndex>90</QualityIndex>
</coordinates>
</coordinates>
</coordReq>
</tns:GetInformationsForCoordinates>
</env:Body>
</env:Envelope>
In comparison to what is sent from SOAP UI I am missing the xmlns:mum namespace - is there anyway I can add it my request so that it is added to each parameter i.e. X, Y QualityIndex - also the tem which is similar to tns in my Savon call is added to the coordReq in SOAPUI but not in my Savon call - is there anyway I can add it?
Also I am having some difficulty in working out how to Build the analysisTypes and AnalysisType part of my request?
From the documentation:
Namespaces
If you don’t pass a namespace to Savon::Client#request, Savon will
register the target namespace (“xmlns:wsdl”) for you. If you did
pass a namespace, Savon will use it instead of the default one. For
example:
client.request :v1, :get_user
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:v1="http://v1.example.com">
<env:Body>
<v1:GetUser>
</env:Body>
</env:Envelope>
You can always set namespaces or overwrite namespaces set by Savon.
Namespaces are stored as a simple Hash.
# setting a new namespace
soap.namespaces["xmlns:g2"] = "http://g2.example.com"
# overwriting the "xmlns:wsdl" namespace
soap.namespaces["xmlns:wsdl"] = "http://ns.example.com"
Apparently, for Savon 2, setting multiple namespaces is impossible:
I found that is not possible (for now) to set multiple namespaces on
version 2 of Savon.
For now i migrate my application on Savon version 1 and it worked =)
To use multiple namespaces you put the following type of code in your client definition
...
:namespaces => {
"xmlns:v2" => "http://v2.example.com",
"xmlns:v1" => "http://v1.example.com" },
...
Related
Objective
Build Soap call via savon v2
What I tried :
my soap call RQ , this is what given in the documentation
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://www.opentravel.org/OTA/2003/05">
<soapenv:Header/>
<soapenv:Body>
<OTA_AirLowFareSearchRQ TimeStamp="2012-04-18T07:30:42.663Z" Target="Production" Version="1.0" PrimaryLangID="en" AltLangID="en" RetransmissionIndicator="false" xmlns="http://www.opentravel.org/OTA/2003/05">
<POS>
<Source ISOCountry="ZA" ISOCurrency="ZAR" DisplayCurrency="ZAR" DisplayRate="1.0" FirstDepartPoint="CPT" FinalDestinationPoint="JNB">
<RequestorID Type="Company" ID="website" ID_Context="ts" TSAffiliateID="<AFFILIATE_ID>" MessagePassword="<AFFILIATE_PASSWORD>">
<CompanyName><AFFILIATE_ID></CompanyName>
</RequestorID>
</Source>
</POS>
<OriginDestinationInformation RefNumber="0">
<DepartureDateTime>2012-07-26T00:00:00CAT</DepartureDateTime>
<OriginLocation LocationCode="CPT" CodeContext="iata"/>
<DestinationLocation LocationCode="JNB" CodeContext="iata"/>
</OriginDestinationInformation>
<OriginDestinationInformation RefNumber="1">
<DepartureDateTime>2012-07-29T00:00:00CAT</DepartureDateTime>
<OriginLocation LocationCode="JNB" CodeContext="iata"/>
<DestinationLocation LocationCode="CPT" CodeContext="iata"/>
</OriginDestinationInformation>
<TravelPreferences>
<FlightTypePref FlightType="Nonstop" DirectAndNonStopOnlyInd="true"/> <!-- This line is optional – include to filter direct flights only -->
<CabinPref Cabin="Economy"/>
</TravelPreferences>
<TravelerInfoSummary>
<AirTravelerAvail>
<PassengerTypeQuantity Code="7" Quantity="0"/>
<PassengerTypeQuantity Code="8" Quantity="0"/>
<PassengerTypeQuantity Code="9" Quantity="0"/>
<PassengerTypeQuantity Code="10" Quantity="1"/>
</AirTravelerAvail>
</TravelerInfoSummary>
</OTA_AirLowFareSearchRQ>
</soapenv:Body>
</soapenv:Envelope>
my Target Url : eg: http://www.example.com?wsdl
operation name : search
#client = Savon.client(wsdl: ' http://www.example.com?wsdl')
#client.call(:search, message: { 'RefNumber' => '1','DepartureDateTime'=>'2014-09-26T00:00:00CAT','ArrivalDateTime'=>'2012-10-26T00:00:00CAT','OriginLocation'=>'CPT','DestinationLocation'=>'JNB' })
what i am getting :
(SOAP:Server) No handlers could be found for unmarshalling the SOAP body payload
The Soap call i built is correct or i have to build the entire xml of Soap body ?
Any help is appreciated !!
My standard answer:
download SoapUI
build a valid SOAP request.
make sure it works
then replicate the request with Ruby/Savon
if it still doesn't work, ask again
I have this method on a web service I'm consuming, using SAVON 3 on Rails 3 web app
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:gpa="http://schemas.datacontract.org/2004/07/Gpa.Comercio.Servicos.Contracts.DTO">
<soapenv:Header/>
<soapenv:Body>
<tem:CalcularCarrinho>
<!--Optional:-->
<tem:carrinho>
<!--Optional:-->
<gpa:CEP>parameter here</gpa:CEP>
<!--Optional:-->
<gpa:CNPJ>parameter here</gpa:CNPJ>
<!--Optional:-->
<gpa:IdCampanha> parameter here </gpa:IdCampanha>
<!--Optional:-->
<gpa:Produtos>
<!--Zero or more repetitions:-->
<gpa:DadosListaProdutoCarrinhoDTO>
<!--Optional:-->
<gpa:Codigo> parameter here </gpa:Codigo>
<!--Optional:-->
<gpa:Quantidade>parameter here</gpa:Quantidade>
</gpa:DadosListaProdutoCarrinhoDTO>
</gpa:Produtos>
</tem:carrinho>
</tem:CalcularCarrinho>
</soapenv:Body>
</soapenv:Envelope>
How should I make a call to this method, considering that the "Produtos" parameter is an array?
I tried:
client.call(:calcular_carrinho){message(id_campanha: 2543, cnpj: '93.528.261/0001-60', cep: '04080013', produtos: ['379457', 1])}
P.S: I made tests with soapUI and the service is working...
I solve this question!
The call to this method:
client = Savon.client(wsdl: "webserviceadress?wsdl")
message = { :carrinho => {cep: '04080013',cnpj: '93.528.261/0001-60', id_campanha: 2543, :produtos => {:dados_lista_produto_carrinho_dto => {codigo: '379457', quantidade: 1}}}}
calc_carrinho = client.call(:method_name, message: message)
According to your question statement I assume you want to use version 3 of gem Savon. The syntax interface for Savon 3 is different from that used in 2.x.
You need to create a Savon-Object first and then create an operation with the corresponding Service/Port data.
client = Savon.new('http://link_to_your_wsdl_here')
operation = client.operation('ServiceName', 'Port', 'custom_action_here')
operation.body = { message: {} }
You can fire up the request by operation.call then.
Since the documentation for Savon 3 is sparse due to its development state I don't know how reliable the above code is. I would be happy seeing someone correcting me if it is not the right way.
I developed one service using websphere application server and Rational application developer(RAD) . I am using SOAP UI to unit test my service. The service is well deployed and getting the accurate results but the problem is in the namespace prefixes.prefixes of response i am getting is different from the prefixes of request namespaces. i.e. if request having namespaces defined as common, domain etc..i am getting response having namespaces as a,b,c ..
the request is as goes here...
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tic="http://www.trrt.com/pos/TicketRemark_v1" xmlns:dom="http://www.tport.com/pos//Domain" xmlns:com="http://www.tralport.com/pos//Common">
<soapenv:Header/>
<soapenv:Body>
<tic:RetrrksRequest Version="1" >
<dom:TicketDocument TicketNbr="6000001"/>
</tic:RetrrksRequest>
</soapenv:Body>
</soapenv:Envelope>
the response is...
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<c:RetrrksResponse Version="1" TimeStamp="2012-08-23T14:15:59.000" xmlns:a="http://www.trrt.com/pos/viewtrip/schema/CommonTypes_v1" xmlns:b="http://www.trport.com/pos/viewtrip/schema/DomainTypes_v1" xmlns:c="http://www.travt.com/pos/viewtrip/schema/TicketRemarksServices_v1">
<a:Success/>
<b:TicketDocument TicketDocumentNbr="6000000000001" TotalDocQuantity="7"/>
<b:BookiID CreateDateTime="2012-08-12T12:40:00.000" PurgeDate="2013-06-20" ID="ABCDEF">
</b:BookiID>
<b:FeeRemarks>
<b:Remark Type="3000">remark text</b:Remark>
</b:FeeRemarks>
</c:RetrirksResponse>
</soapenv:Body>
</soapenv:Envelope>
This is not a problem. The namespace prefix may be arbitrary, so long as it references the correct namespace. One should not depend on the particular choice of a namespace prefix. Any code that does rely on a choice of prefix will likely suffer interoperability problems.
I am getting number format exception while trying to get the issue details by using id.
RemoteIssue ri = jira.getIssueById(JIRAtoken, string.Format(IssueKey));
here jiratoken is string. But giving exception. Any one have any idea?
I had the same problem, using the SOAP Web Service API of JIRA (4).
I solved it by using getIssue instead of getIssueById. With getIssue, JIRA expects the key like MYPROJECT-3.
Now I send a request like this, and it works :
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://soap.rpc.jira.atlassian.com">
<soapenv:Header/>
<soapenv:Body>
<soap:getIssue soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<in0 xsi:type="xsd:string">MyAuthToken</in0>
<in1 xsi:type="xsd:string">MYPROJECT-1</in1>
</soap:getIssue>
</soapenv:Body>
</soapenv:Envelope>
I seem to be getting this error message:
(a:ActionNotSupported) The message with Action 'GetServices' cannot be
processed at the receiver, due to a ContractFilter mismatch at the
EndpointDispatcher. This may be because of either a contract mismatch
(mismatched Actions between sender and receiver) or a binding/security
mismatch between the sender and the receiver. Check that sender and
receiver have the same contract and the same binding (including
security requirements, e.g. Message, Transport, None).
I assume it is something to do with the security/binding setup.
My connection uses HTTP, with basichttpbinding. I've done a lot of searching for the answer, as I always do, but am unable to fix it, and no one here has expertise on Ruby on Rails.
Help would be appreciated.
Below is my code, in Ruby on Rails, which initialises the service and then calls it. Note: I can connect to it fine. It has successfully reported the available methods. Just calling the methods seems to be the problem. I have successfully connected to online test services using the same code. And I use Savon.
def test
puts "web_service: IN"
client = Savon::Client.new do
wsdl.document = "http://hidden.co.uk/myService.svc?wsdl"
end
#response = client.request "GetServices", :xmlns => "http://tempuri.org/" do
soap.header = {}
soap.body = {
"CostCentreNo" => 1,
"filter" => 0
}
end
puts '##########################'
puts #response.to_hash;
end
Below is what my Ruby on Rails sends:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:wsdl="http://tempuri.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<GetServices xmlns="http://tempuri.org/">
<CostCentreNo>1</CostCentreNo>
<filter>0</filter>
</GetServices>
</env:Body>
</env:Envelope>
This is what WCF test client sends, (which works)
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IIBCSServices/GetServices</Action>
</s:Header>
<s:Body>
<GetServices xmlns="http://tempuri.org/">
<CostCentreNo>0</CostCentreNo>
<filter>0</filter>
</GetServices>
</s:Body>
</s:Envelope>
It seems to be the way it was being called... Something so simple.
The override Stated on the SAVON Tutorial, recommended if you have an uppercase starting camelcase doesnt work. Maybe the tutorial is outdated. (Note, :wsdl IS required in my case)
So this was not working:
response = client.request :wsdl, "GetCustomerCentreDetails"
Changing it to:
response = client.request :wsdl, :get_customer_centre_details
Then obviously I need a body added to it, and header etc.
The assumption that caused me confusion : Being able to get the WSDL does not mean you are connected to the webservice.
it seems you're missing this part
<Action s:mustUnderstand="1" ...>
you should insert something like the following into your request
soap.header = {"Action" =>
{'env:mustUnderstand' =>
'http://tempuri.org/IIBCSServices/GetServices',
attributes! => { 'mustUnderstand' => "1", 'xmlns' => "..." }
}