Reputation: 43
Spent the last day banging my head with this, and would appreciate any help!
I am building an application which consumes a 3rd party SOAP web service. This is based on node.js and uses node-soap. Unfortunately the WSDL file is a little broken, and I need to work my way around it.
This is the code I am using:
var url = 'http://domainexample.com/ws/connectionService.cfc?wsdl';
var session = 'super secret string'
var args = { connectionID: session }
soap.createClient(url, function (err, client) {
client.connectionService_wrapService['connectionservice.cfc'].isConnected(args, function (err, result) {
console.log(result);
});
});
This is the error I get. Most of the other methods work fine:
org.xml.sax.SAXException: Deserializing parameter \'connectionID\': could not find deserializer for type { http://www.w3.org/2001/XMLSchema}anyType'
This is the message generated by the method:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:impl="http://rpc.xml.cfml/
ws/ConnectionService.cfc" xmlns:intf="http://rpc.xml.cfml/ws/ConnectionService.cfc">
<soap:Body>
<impl:isConnected>
<connectionID>super secret string</connectionID>
</impl:isConnected>
</soap:Body>
</soap:Envelope>
I found that the WSDL file does not have a proper type attribute defined for the connectionID parameter for some of the methods (such as this one). It should be xsd:string, which is what it is for the methods I call that do work.
After some playing around with SOAP UI I found adding a type attribute (xsi:type=xsd:string) to the connectionID part, and adding a schema (xmlns:xsd="http://www.w3.org/2001/XMLSchema") fixes it. This is the XML I need to generate:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:impl="http://rpc.xml.cfml/
ws/ConnectionService.cfc" xmlns:intf="http://rpc.xml.cfml/ws/ConnectionService.cfc">
<soap:Body>
<impl:isConnected>
<connectionID xsi:type="xsd:string">auth-string-here</connectionID>
</impl:isConnected>
</soap:Body>
</soap:Envelope>
But I can't figure out for the life of me how I can do it via node soap. I tried to add a type using the attributes key, however it only seems to work when I have parent node and child node in the arguments.
So, if I pass this down:
var args = {
test: {
connectionID:
{
attributes: {
'xsi:type': 'xsd:string'
},
$value: session
}
}
};
I get the following:
<impl:isConnected>
<test>
<connectionID xsi:type="xsd:string">super secret string</connectionID>
</test>
</impl:isConnected>
But I only need one level, like this:
var args = {
connectionID:
{
attributes: {
'xsi:type': 'xsd:string'
},
$value: session
}
};
So I get this:
<impl:isConnected>
<connectionID xsi:type="xsd:string">super secret string</connectionID>
</impl:isConnected>
But that doesn't seem to be happening. In fact, It doesn't add a type attribute at all when I keep it to a single node. I also need to figure out a way of adding the extra schema in the call. I worked around it by manually adding it in the soap-node core code, but that isn't clean at all (I can live with it though).
Any ideas? I'm fairly new to SOAP, and I'm not having much luck at the moment.
Thanks!
Upvotes: 3
Views: 5632
Reputation: 1070
For adding the schema you can do it after you have access to your client like shown in this answer: https://stackoverflow.com/a/78491541/2087214
Here it would be:
if (!client['wsdl'].xmlnsInEnvelope.includes('xmlns:xsd=')) {
client['wsdl'].xmlnsInEnvelope += ' xmlns:xsd="http://www.w3.org/2001/XMLSchema"';
}
The
const args = {
connectionID:{
attributes: {
'xsi:type': 'xsd:string'
},
$value: session
}
}
Should just work, because I now also do it exactly like this for my own functions. Not sure if in the last years they updated their client, so that it now works?
Upvotes: 0
Reputation: 763
Currently Node-Soap does not allow to pass the "attributesKey" value at the client options and does not use one by default.
The only way I could make it work is by defining my own WSDL object (with open_wsdl(uri, options, callback) function), pass options at the second parameter (not including "attributesKey" as it won't assign it) but then to the generated object assign it like this:
open_wsdl(wsdlUrl, setupSoapWsdlConfig() /* Here you can pass other params as valueKey and xmlKey but not attributesKey */, (err, wsdl: WSDL) => {
if ( err ) { reject(err); }
this.wsdl = wsdl;
wsdl.options.attributesKey = '$attributes'; // Specify attributesKey
resolve(wsdl);
});
Upvotes: 1
Reputation: 87
Couple of things I made sure: I included following namespace in my wsdl definition:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Also, in the response make sure you have following namespace in Envelope:
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
I had to manually fix couple of things in node soap library too at following location lib/wsdl.js WSDL.prototype._xmlnsMap function to add above namespaces
I added below code to make it happen:
WSDL.prototype._xmlnsMap = function() {
var xmlns = this.definitions.xmlns;
var str = '';
for (var alias in xmlns) {
if (alias === '' || alias === TNS_PREFIX) {
continue;
}
var ns = xmlns[alias];
switch (ns) {
case "http://www.w3.org/2001/XMLSchema-instance" : //xsi support
case "http://www.w3.org/2001/XMLSchema" : //xsd support
str += ' xmlns:' + alias + '="' + ns + '"';
continue;
case "http://xml.apache.org/xml-soap" : // apachesoap
case "http://schemas.xmlsoap.org/wsdl/" : // wsdl
case "http://schemas.xmlsoap.org/wsdl/soap/" : // wsdlsoap
case "http://schemas.xmlsoap.org/wsdl/soap12/": // wsdlsoap12
case "http://schemas.xmlsoap.org/soap/encoding/" : // soapenc
continue;
}
if (~ns.indexOf('http://schemas.xmlsoap.org/')) {
continue;
}
if (~ns.indexOf('http://www.w3.org/')) {
continue;
}
if (~ns.indexOf('http://xml.apache.org/')) {
continue;
}
str += ' xmlns:' + alias + '="' + ns + '"';
}
return str;
};
Updated response:
<soap:Body><IsAliveResponse><return xsi:type="xsd:string">success</return>
</IsAliveResponse></soap:Body>
This is what I am using in Service file:
return:{
attributes: {
'xsi:type': 'xsd:string'
},
$value: healthCheck
}
Upvotes: -1