How to consume wsdl webservice through node js - node.js

I am using strong-soap node module i want to make call to webservice, I have wsdl file.
var soap = require('strong-soap').soap;
var WSDL = soap.WSDL;
var path = require('path');
var options = {};
WSDL.open('./wsdls/RateService_v22.wsdl',options,
function(err, wsdl) {
// You should be able to get to any information of this WSDL from this object. Traverse
// the WSDL tree to get bindings, operations, services, portTypes, messages,
// parts, and XSD elements/Attributes.
var service = wsdl.definitions.services['RateService'];
//console.log(service.Definitions.call());
//how to Call rateService ??
});

I'm not sure about how strong-soap works.
But, I have some implementations of SOAP using node-soap.
Basically, the node-soap package uses Promises to keep the requests concurrent.
var soap = require('soap');
var url = 'http://www.webservicex.net/whois.asmx?WSDL';
var args = {name: 'value'};
soap.createClient(url, function(err, client) {
client.GetWhoIS(args, function(err, result) {
console.log(result);
});
});

Lets use the following sample SOAP service:
Get domain name registration record by Host Name / Domain Name (WhoIS)
To judge from your code you'd like to use a .wsdl file available locally, so saving it:
mkdir wsdl && curl 'http://www.webservicex.net/whois.asmx?WSDL' > wsdl/whois.wsdl
Now lets use the following code to query it:
'use strict';
var soap = require('strong-soap').soap;
var url = './wsdl/whois.wsdl';
var requestArgs = {
HostName: 'webservicex.net'
};
var options = {};
soap.createClient(url, options, function(err, client) {
var method = client['GetWhoIS'];
method(requestArgs, 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));
});
});
It would produce some meaningful results.
WSDL.open you're trying to use is meant for working with WSDL structure
Loads WSDL into a tree form. Traverse through WSDL tree to get to
bindings, services, ports, operations, and so on.
You don't necessarily need it to call a service

Related

Receiving XML request in strong-soap

I am currently developing a NodeJS project with strong-soap library to receive and transmit SOAP requests and responses. Before asking question, i want to present code sample to ask my question efficiently.
server.js
//Address of this project is http://localhost:8080
const soap = require('strong-soap');
const http = require('http');
const fs = require('fs');
let myService = { //My SOAP server's service (group of methods)
Method:
function(data) //My question literally and directly related with data
{
//... Function content.
}
};
let xmlFile = fs.readFileSync('sample.wsdl');
let path = '/wsdl';
http.createServer(function (req, res) {
let soapServer = soap.listen(server, '/wsdl', myService, xmlFile);
}).listen(8080);
Assume that i have a server with codebase which is is seen above. And assume that have another Node.js project (or another .js file) which send request and transmit response from this server.
client.js
const soap = require('strong-soap');
soap.createClient('http://localhost:8080/wsdl', {forceSoap12Headers: true}, function(error, client){
if(error)
{
reject(error);
//res.sendStatus(404);
//console.log(error);
}
else{
client.Method(requestArgs, function(err, result, envelope) {
//I want to be able to sent an XML data as requestArgs
// Result in SOAP envelope body which is the wrapper element.
// In this case, result object corresponds to GetCityForecastByZIPResponse.
console.log(JSON.stringify(result));
}, null, customRequestHeader);
}
});
My question is: how i can send an XML in client.js? Or how i can receive requests in XML format without any problem in server.js? Most probably, i will deal with raw XML requests, and i want to deal with both XML and JSON requests? Help me developers!

Angular 13 type conversion error from backend that returns BLOBs

Angular and node's aren't my strong suits and I've had the misfortune of inheriting an angular 13 project where I'm tasked with implementing a minor JasperReport integration.
To put it brief, 3 different fields from the form are grouped into params that get sent to the backend NODEJS server, which sends it to JasperReports Rest_v2 API which then generates a report with them, however the trouble I'm having is taking return data BLOB and converting it to a PDF file that appears as a file download browser side.
My NODEJS method for connecting to jasper reports rest api:
app.post('/api/accounts/report',(req,res)=>{
//Params from the API call
var acc_id = parseInt(req.body.params['acc_id']);
var start_date = req.body.params['start_date'];
var end_date = req.body.params['end_date'];
var sage_num = req.body.params['sage_num'];
var request = require("request");
qs = require('querystring'),
request = request.defaults({
jar: true
});
//Login call to jasper server
request.post({url: jasper_login, qs: {j_username:jasper_usr, j_password:jasper_pwd}},
function(err, resp, body) {
if(err) {
return console.error(err);
}
//actual report call
request.get(jasper_hst,
function (error, response, body1) {
if (error){
console.log(response.statusCode);
console.log(error);
}
res.type('arraybuffer').send(response.body);
})
}
)
});
this method returns the BLOB of data that is the PDF file e.g.:
Sample Data
However the problem I'm having now is a type conversion error as soon as I call the backend:
console error
My ts methods:
pdfExportBtn(e:any){
//harcoded params for testing
var params={"acc_id":"18785","start_date":"2022/05/01, 00:00:00","end_date":"2022/06/01, 00:00:00","sage_num":"12341234"};
//call the API and generate report
this.getReport(params).subscribe((response)=>{
const newBlob = new Blob([response], {type: 'application/pdf'});
const downloadLink = document.createElement('a');
downloadLink.target = '_self'; const fileName = acc_name+' Transaction Summary '+date1+' to '+date2+'.pdf';
const data = window.URL.createObjectURL(newBlob); downloadLink.href = data;
downloadLink.download = fileName; document.body.appendChild(downloadLink);
downloadLink.click();
});
}
getReport(params){
return this.http.post<Blob>(`${environment.apiUrl}/api/accounts/report`,{responseType: 'arraybuffer'},{params});
}
But I'm specifying the return types as a blob and the 'array buffer' so I have no clue why its trying to parse into JSON.

node-soap -- how to capture soap request before it is handled by soap listener

I created a soap server in nodejs using the node-soap module. But I get an error indicating there is some problem in the incoming soap xml (listed below).
< soap log: { Fault: < { faultcode: 500, < faultstring:
'Invalid XML', < detail: 'Error: Non-whitespace before first
tag.\nLine: 1\nColumn: 1\nChar: -', < statusCode: undefined } }
When I searched around in google, it indicated that it is the problem of BOM (Byte Order Mark) which the windows OS inserts into the unicode buffer. Most of the solutions suggested to replace/remove this BOM before calling the xml parser.
Now, when I am using node-soap module, I am unable to figure out where to apply this fix, below being my server code.
/**
* Simple demonstration of soap service
**/
var soapService = require("./rv.js");
var xml = require('fs').readFileSync('./mmsxmlpushservicews.wsdl.xml', 'utf8');
var express = require('express');
var bodyParser = require('body-parser');
var soap = require('soap');
var app = express();
app.use(bodyParser.raw({type: function() { return true; }, limit: '5mb' }));
app.listen(8001, function(err) {
if (err) {
console.error("error:", err);
process.exit(1);
}
var server = soap.listen(app, '/smshttp/soapws', soapService, xml);
server.log = function(type, data) {
//console.log("soap log:", data);
}
console.log("service running on port 8001...");
});
In the above soap server code, is there an event / callback hook that I can make use of to modify the soap request buffer, before the soap server performs its parsing?
If yes, where and how should I be doing it?
Add this to your code after this line 'app.use(bodyParser.raw({type: function() { return true; }, limit: '5mb' }));'
app.use(function(req, res, next) {
var body = req.body.toString();
var body = body.replace('\ufeff', '');
req.body = Buffer.from(body);
next();
});
This hook in express allows you process every request, evaluate which urls have been called and safely forward to the next listener with 'next()'.
But consider that this function will be called for EVERY request, so don't forget to filter only those, where you do need to clean the string.

NodeJS - How to get the HTTP header of a SOAP webservice's response

When consuming a SOAP webservice in NodeJS with the 'soap' package. Like so:
var soap = require('soap');
var url = 'http://example.com/wsdl?wsdl';
var args = {name: 'value'};
clientsoap.createClient(url, function(err, client) {
client.MyFunction(args, function(err, result, raw, soapHeader) {
console.log(result);
});
});
How do I get the HTTP header of the response to MyFunction? Specifically, I want the Cookie parameter inside the HTTP Header.
Is this something Node/Express can do? Or Is there another package I need to achieve this?
Thanks in advance.
The NodeJS soap module stores the last response headers against the client when invoking a method, so just access it in your callback:
var soap = require('soap');
var url = 'http://somewhere.com?wsdl';
var args = {name: 'value'};
soap.createClient(url, function(err, client) {
client.myFunction(args, function(err, result) {
console.log(client.lastResponseHeaders);
});
});
I ran into the same issue and have been working on it for a while now. I have made some progress to where I can see the cookies but they aren't coming through exactly as I expected. I'm not sure if I'm doing something wrong or it's specific to the service WSDL I'm trying to hit. But here's my solution...
soap.createClient(pathOrUrlToWSDL, function(err, client) {
client.myFunction(args, function(err, result, raw, soapHeader) {
console.log(err, result, raw, soapHeader);
});
// -- should reach the response before the callback in client.myFunction()
client.on('response', function(envelope, message) {
// -- couldn't find documentation on this function, so I just named the variables 'envelope' and 'message'
console.log(message.headers);
});
});

ExpressJS - contact external API

Here is the thing :
I have a client which sends data to a server. This server has to contact an external A.P.I. and send back its response to the client. I just can't figure out how and where I can contact the external A.P.I once the server has got the client data.
I route client data like this :
app.post('/getAutoComplete', routes.read);
routes.read retrieves the data within req.body. With my nodejs version (without express framework), I then request the api this way :
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
The problem is that i'd like to use native expressJS method like app.post but I don't know how because :
Express (app) object is not available here (declared in app.js but not in the route file)
I don't know how to send POST data with app.post
Any suggestion ?
app.post('/getAutoComplete', routes.read);
// assuming routes.read lookes something like this
routes.read = function read(req, res) {
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
};
Also check out https://github.com/mikeal/request It's the de-facto module for doing web requests in node.
routes.read is a function. You can call it with extra parameters, so for example
app.post('/getAutoComplete', function(req,res) {
var q = req.query.q; // or whatever data you need
routes.read(q, function(err, response) {
if (err) throw err;
return res.json(response);
});
});
Now make the routes.read function use the first parameter as the query and when it's gathered the response from the remote API, call the second parameter with any error as the first parameter and the response as the second one.
Update This answer has already been picked as an answer, but it'd be more helpful if I showed an example of routes.read, too:
routes.read = function(q, cb) {
// pretend we calculate the result
var result = q * 10;
if (result > 100) {
// call the callback with error set
return cb("q value too high");
}
// all is well, use setTimeout to demonstrate
// an asynchronous return
setTimeout(function() { cb(null, result) }, 2000);
};

Resources