Node.js soap request remove namespace from argument - node.js

I am unable to send the correct argument to the service.
Code used:
var soap = require('soap');
var url = 'http://example.com';
soap.WSDL.prototype.ignoredNamespaces = ['targetNamespace', 'typedNamespace'];
var args = {'name':'test'};
soap.createClient(url, function(err, client) {
client.Hello(args, function(err,result,res){
console.log(result);
console.log(client.lastRequest);
});
});
The Hello-function should return string "Hello test !". However, I get:
'Hello null !'
The request being sent is:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ....><soap:Body>
<tns:Hello xmlns:tns="http://example/">
<tns:name>test</tns:name>
</tns:Hello></soap:Body></soap:Envelope>
where
test
is the interesting part. The service is expecting
<name>test</name>
without namespace (i tested this with http://www.soapclient.com/)
So, the question is: how do I send the request argument without tns attached? (tns:name => name) Thanks!

The correct way to override namespace is to send the parameters like this:
var params = { ':name' : 'test' }
It's in documentation: Overriding the namespace prefix

In your code instead of passing argument as
var args = {'name':'test'};
try
var args = {arg0: 'testName'};
I am not an expert but it worked for me to pass an argument from node.js while invoking SOAP client.

Related

nodejs - SOAP call is failing with 500 error using npm package strong soap

I am trying utilize the npm strong-soap package to execute a SOAP call in nodejs.
I am getting an error as below (first few lines of error is below)
"statusCode":500,"body":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SOAP-ENV:
Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <SOA
P-ENV:Body>\n <SOAP-ENV:Fault>\n <faultcode>BWENGINE-100031</f
aultcode>\n <faultstring>Output data invalid</faultstring>\n
<faultactor>JOBID_15734</faultactor>\n <detail>\n <
ns0:Error_Short_Message xmlns:ns0=\"http://xmlns.example.com/unique/default/name
space/1073503881527\">\n <ns0:key>JOBID_15734</ns0:key>\n
<ns0:msg_code>BWENGINE-100031</ns0:msg_code>\n
<ns0:message>Output data invalid</ns0:message>\n
The client code is as below:
var soap = require('strong-soap').soap;
var url = 'D:/Workspace/Projects/Sample.wsdl';
var args = {arg1: '6564',arg2:'ONE'};
var soapHeader = {
'header1': 'value1',
'header2': 'value2',
'header3': 'value3',
};
var options = {};
soap.createClient(url,options,function (err, client) {
client.setEndpoint('http://hostname:Port/SampleService/Service');
var method = client['GetDataMethod'];
method(args,function (err, result, envelope, soapHeader) {
//response envelope
//console.log('Response Envelope: \n' + envelope);
//'result' is the response body
console.log('Result: \n' + JSON.stringify(result));
})
});
Any suggestions on the reason for this error would be helpful.
UPDATE:
I was able to fire the request and get response if I build the args as something like below:
var args = {
"namespace":{
"requestHeader":{
"header1": "value1",
"header2": "value2",
"header3": "value3"
},
"arg1": "6564",
"arg2":"ONE"}
};
But any reason why strong-soap is unable to setup the namespace based on wsdl content? Programmatically identifying the exact namespace among 20-30 namespaces in wsdl seems to be cumbersome task.

SOAP Request using nodejs

Hi can anyone help me out.
how to request soap web service and get the xml response.
Senario:
Using soap ui im sending wsdl url with username, password authentication and also i will send soap xml data and i gets reponse.
Same thing how to achive using nodejs or sails.
In SoapUi My soap xml request is like
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tier="http://HCSLN9191-GMS.gois.ito.unisys.com/Tier1ICLStd:Tier1ICLMB_StdDispatch">
<soapenv:Header/>
<soapenv:Body>
<tier:UnisysMB_Dispatch>
<PayLoad>SomeData</PayLoad>
</tier:UnisysMB_Dispatch>
</soapenv:Body>
</soapenv:Envelope>
And My Soap Authentication is like
$UserName : xyz & password:xyz
My wsdl url is
http://esbuatt1wm.ito.xyz.com:7001/ws/Tier1ICLStd_New:Tier1ICLMB_StdDispatch_New?WSDL
After provides this information i am getting xml response like
<ser-root:CommAck xmlns:ser-root="http://HCSLN1181-GMS.gois.ito.unisys.com/Tier1ICLStd_New:Tier1ICLMB_StdDispatch_New" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CommAck>
<MB_UUID>cbbb683d-e9b1-4d12-b0db-8006134aad27</MB_UUID>
<ServiceID>McDonalds</ServiceID>
<Acknowledge>0</Acknowledge>
<Comment>Payload does not contain the pattermatch xpath.</Comment>
</CommAck>
</ser-root:CommAck>
My Question is How to get that above xml response using node easy soap,
i am new to soap concept. can anyboud help me out to give me the proper snippet for the above senario.....
You can use this package https://www.npmjs.com/package/soap. Examples are in the same link. I have pasted below some of the contents:
Install with npm:
npm install soap
Example:
var soap = require('soap');
var url = 'http://example.com/wsdl?wsdl';
var args = {name: 'value'};
soap.createClient(url, function(err, client) {
client.MyFunction(args, function(err, result) {
console.log(result);
});
});
BasicAuthSecurity
client.setSecurity(new soap.BasicAuthSecurity('username', 'password'));
You can use Axios a promise based Nodejs package.
an Example:
const baseURL = '';
const apiKey = '';
const xmlBody = `XML body here // you can also add api key using ${apiKey} like this if needed`;
axios.post(BaseURL,xmlBody,{
headers: {
'Content-Type': 'text/xml'
}
}
).then(response => {console.log(response.data)}
).catch(err => {console.log(err)});
You can use the soap module. I had to eventually use it so documented it below in the link provided.
for username and password, if your WSDL is password protected then you would also need to set the correct wsdl_headers in the client that you would create with node-soap
check out this answer:https://stackoverflow.com/a/29036380/4157003
Additionally, You also need to set the correct security mechanism before using any service
client.setSecurity(new soap.BasicAuthSecurity('username', 'password'));
You can check this link for more info
https://codecalls.com/2020/05/17/using-soap-with-node-js/
You can use the easy-soap-request npm package.
If you want to create the SOAP header passwordDigest in nodejs,
const crypto = require('crypto');
function passwordDigest(created, nonce, pass) {
// Password_Digest = Base64 ( SHA-1 ( bytes(decode64(nonce)) + bytes(created) + bytes(password) ) )
let pd = Int8Array.from([...Int8Array.from(Buffer.from(nonce, 'base64')),
...Int8Array.from(Buffer.from(created)),
...Int8Array.from(Buffer.from(pass))]);
pd = crypto.createHash('sha1').update(pd).digest('base64');
return pd;
}
More detailed explanation on this post
https://stackoverflow.com/a/66824784/15485314

How can I add "namespace" to request in node soap

I created web service object from wsdl file and call it like in below. I also print result. this code does not work. web server returns error. because, request has not namespace.
soap.createClient(__dirname + '/wsdl/getCustomerDetails.wsdl', function(err, client) {
.
.
var params= {"custId":"123"};
client.getCustomerDetails.getCustomerDetailsPort.getCustomerDetails(params,function(err,result){
console.log("lastRequest:"+client.lastRequest);
if (err != null)
console.log("error:"+JSON.stringfy(error));
});
}
here what I see in the last request
<soap:... xmlns:tns="http://example.com/api/getCustomerDetails/V01" >
....
<soap:Body>
<getCustomerDetailsRequest>
<custId>123</custId>
</getCustomerDetailsRequest>
</soap:Body>...
but it has to be
<soap:... xmlns:tns="http://example.com/api/getCustomerDetails/V01" >
....
<soap:Body>
<tns:getCustomerDetailsRequest>
<tns:custId>123</tns:custId>
</tns:getCustomerDetailsRequest>
</soap:Body>...
as you see, soap module does not add tns namespace to the request. I tried var params= {"tns:custId":"123"};, it adds namespace to the parameter, but still it does not add namespace to the request, getCustomerDetailsRequest. because of that, I get Unexpected element getCustomerDetailsRequest found. Expected {http://example.com/api/getCustomerDetails/V01}getCustomerDetailsRequest.
how can I force to add this namespace to the method itself ?
I found how I can do that. I think it does not work in default because of a bug in "soap" module. In default, it does not add namespace to the request body. "soap" uses "tns" in default as namespace. there is an option in wsdlOptions. it is overrideRootElement. If you try to override overrideRootElement with tns, it does not add tns to the request body. You have to use different namespace in overrideRootElement. Here my solution,
I first create my wsdlOptions object.
var wsdlOptions = {
"overrideRootElement": {
"namespace": "myns",
"xmlnsAttributes": [{
"name": "xmlns:myns",
"value": "http://example.com/api/getCustomerDetails/V01"
}]
}
};
and then use it when I create soap client,
soap.createClient(__dirname + '/wsdl/getCustomerDetails.wsdl',wsdlOptions, function(err, client) {
.
.
.
}
);
It makes request body uses myns as namespace of root element. Now, I have to modify parameters' namespace, so I defined parameters as
var params= {"myns:custId":"123"};
now, It creates request as
<soap:... xmlns:tns="http://example.com/api/getCustomerDetails/V01" >
....
<soap:Body>
<myns:getCustomerDetailsRequest xmlns:myns="http://example.com/api/getCustomerDetails/V01">
<myns:custId>123</tns:custId>
</myns:getCustomerDetailsRequest>
</soap:Body>...
and, now webserver accepts it.
keep in mind, even tns is defined in the root, it is not added to the request body automatically. Also, if you try to override it in wsdlOptions by tns again, it still does not work. You have to use different value as namespace, like myns
I dwelt sometime on this problem until I saw that the lib get the namespaces from the parsed WSDL (this.wsdl.xmlnsInEnvelope)
xml = '<?xml version="1.0" encoding="utf-8"?>' +
'<' + envelopeKey + ':Envelope ' +
xmlnsSoap + ' ' +
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
encoding +
this.wsdl.xmlnsInEnvelope + '>' +
Then I saved the WSDL inside my project (loading from there) and inserted the namespace I wanted. That worked for me.

Connecting to a web service using SOAP

I am currently working on a node based application trying to make a request to a SOAP based service. I am making use of the node-soap module to work through this.
https://github.com/vpulim/node-soap
Currently i have the following implementation
var soap = require('soap');
var url = 'http:/xxxx/xxxx/xxxx?WSDL';
var appKey = 'ABYRCEE';
var xml = {
appKey: appKey,
mac: 'xxxxxxxx'
}
soap.createClient(url, function(err, client){
//console.log('Client:', client);
client.getAllDocsisVideoInfo(xml, function(err, result){
if(err){
console.log(err);
}
});
});
For the service to respond, i have a sample request in xml format, as the following
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:doc="http://xxx.xxx.com">
<soapenv:Header/>
<soapenv:Body>
<doc:getAllDocsisVideoInfo>
<appKey>"appKey"</appKey>
<mac>xxxxxxx</mac>
</doc:getAllDocsisVideoInfo>
</soapenv:Body>
</soapenv:Envelope>
As you can see from the above that i have to pass in appKey and mac values and upon a successful request this will send back successful response in xml format with the appropriate response.
I am able to see client object return back with the appropriate functions, but upon calling the client.getAllDocsisVideoInfo(....), i seem to see the following error
S:Client: Cannot find dispatch method for {}getAllDocsisVideoInfo
I am not sure of the why? Is it because of the way i am passing in the xml object, how do i pass in the sample request?
Looking at the node-soap api:
https://www.npmjs.com/package/soap
It looks like you have to call the function in the following manner:
client.getAllDocsisVideoInfo(xml, function(err, result, raw, soapHeader){
})
If you want to call it like you had it in your code, then I think you need to use the following:
Copy and paste from the API...
client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
// result is a javascript object
})
So after spending hours on this and banging my head, i was able to get a successful response by overriding the namespace prefix, by removing the namespace prefix.
For example, the following object needed to be passed as
var xml = {
':appKey': appKey,
':mac': 'xxxxxxxx'
}
Instead
var xml = {
appKey: appKey,
mac: 'xxxxxxxx'
}
This piece of the node-soap documentation [https://github.com/vpulim/node-soap#overriding-the-namespace-prefix][1] helped in figuring out the issue.

Node.js SOAP Call with Complex Types

I am currently attempting to use node-soap (https://github.com/milewise/node-soap) to make calls to Authorize.net's SOAP server. However, I cannot seem to get my client code pass the proper parameters. I know that the function is calling the server since I get a server error response.
When I examine the WSDL, I notice that the server call requires ComplexType parameters. Is there a way to create the ComplexTypes that I need or can I just use Javascript objects? Here is my current code:
var soap = require('soap');
var url = 'https://api.authorize.net/soap/v1/Service.asmx?WSDL';
soap.createClient(url, function(err, client) {
var args = {
merchantAuthentication: {
name: '285tUPuS',
transactionKey: '58JKJ4T95uee75wd'
}
};
client.Service.ServiceSoap12.GetTransactionDetails(args,
function(err, result) {
if (err) {
console.log(err);
} else {
console.log(result.GetTransactionDetailsResult[0].messages);
}
});
});
The node-soap module is converting your JavaScript object to XML before sending the transaction to the server. It wraps the request in an xml element as outlined by the wsdl. Here is an example of what might be produced by node-soap when passing the object you provided (important to note the outer element is created by the node-soap module according to the wsdl):
This example is using the wsdl for the CyberSource API
<data:requestMessage xmlns:data="urn:schemas-cybersource-com:transaction-data-1.93" xmlns="urn:schemas-cybersource-com:transaction-data-1.93">
<data:merchantAuthentication>
<data:name>285tUPuS</data:name>
<data:transactionKey>58JKJ4T95uee75wd</data:transactionKey>
</data:merchantAuthentication>
</data:requestMessage>
Also, I don’t know exactly how the Authorize.net api works, but it sounds like you might want to check out using username token authentication if necessary:
client.setSecurity(new soap.WSSecurity('username’, ‘password’));

Resources