I am trying to call soap web service using node. I have used soap and request packages.
Below is the code snippet :
var express = require('express');
var Promise = require("bluebird");
var app = express();
var soap = require('soap')
var url = 'http://example.com?WSDL';
let request = require('request');
let request_with_defaults = request.defaults({
'proxy': 'http://example.com:80',
'timeout': 5000,
'connection': 'keep-alive'
});
let soap_client_options = {
'request': request_with_defaults
};
var args = {
requestId: '1406303'
};
soap.createClient(url, soap_client_options, function(err, client) {
var soapHeader = {
"Username": "test",
"Password" : "test"
};
client.addSoapHeader(soapHeader);
client.getESSJobStatus(args, function(err, result) {
if(err){
console.log('Error occured');
}
console.log(result);
});
})
here i am getting error :
throw new TypeError("Cannot promisify an API that has normal methods with '%s'-suffix\u000a\u000a See http://bluebirdjs.com/docs/error-explanations.htmlX\u000a"
TypeError: Cannot promisify an API that has normal methods with 'Async'-suffix
See http://bluebirdjs.com/docs/error-explanations.html
I have checked this url. it is saying that async task gets created which is not able to call. But i am not able to relate this.
can anyone help me with code how can i resolve this issue?
Try Promise.promisifyAll(require('soap'), {suffix: 'MySuffix'});
Related
I'm creating a script which is going to automatically receive data from API and store it in MongoDB at specific UTC time.
I use Node-Schedule for scheduling a task at specific time.
CoinMarketCap API for receiving a real time data.
Problem: I receive an undefined in console every second(since the node-schedule is configured to call the code every second). I was looking for any syntax errors or errors in API and wasn't successful. I understand that I receive undefined cause the function doesn't return anything.
Currently doesn't have any ideas what wrong with it at all.
All API keys and DB username password was correct I checked it as well.
Goal: To have the script which is automatically receives data from API and stores it MongoDB collection.
Full Code
const { MongoClient } = require('mongodb');
const schedule = require('node-schedule');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const saveToDatabase = function(BTCdata) {
const url = 'mongodb+srv://name:password#cluster0-1kunr.mongodb.net/<dbname>?retryWrites=true&w=majority';
MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, db) => {
if (err) throw err;
const dbo = db.db('Crypto');
const myobj = { Name: 'BTC', Volume: 'BTCdata' };
dbo.collection('Crypto-Values').insertOne(myobj, (error, res) => {
if (error) throw error;
console.log('1 document inserted');
db.close();
});
});
};
function request(method, url) {
return new Promise(((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = resolve;
xhr.onerror = reject;
xhr.send();
}));
}
const j = schedule.scheduleJob('* * * * * *', () => {
request(
'GET',
'http://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?CMC_PRO_API_KEY=API-KEY-HERE',
)
.then((r1) => {
const x1 = JSON.parse(r1.target.responseText);
const BTCdata = x1.data.find((d) => d.symbol === 'BTC').quote.USD.volume_24h; // creating a variable to store a BTC request from API
console.log(BTCdata);
// Saving to database
saveToDatabase(BTCdata);
})
.catch((err) => {
console.log(err);
});
});
EDIT1:
This is a console log of x1 value.
EDIT2:
Was missing this part -
var request = require('request');
After it was added I start receiving a new error in my console which is :
events.js:287
throw er; // Unhandled 'error' event
^
Error: Invalid URI "GET"
at Request.init
at new Request
at request
at Job.job
at Job.Invoke
at Users/path to node modules/node-schedule
at Timeout.onTimeout
EDIT3:
After correction to the code with #Sureshprajapati answer.
New error appears - TypeError: Cannot read property 'responseText' of undefined
Trying to find solution by myself. Still looking for any advice. Thank you.
var requestPromise = require('request-promise');
requestPromise.get({
uri: 'http://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?CMC_PRO_API_KEY=API-KEY-HERE',
json: true
}).then(r1 => {
const x1 = JSON.parse(r1.target.responseText);
const BTCdata = x1.data.find(d => d.symbol === 'BTC').quote.USD
.volume_24h; // creating a variable to store a BTC request from API
console.log(BTCdata);
// Saving to database
saveToDatabase(BTCdata);
}).catch(err => {
console.log(err);
});
request supports both streaming and callback interfaces natively. If you'd like request to return a Promise instead, you can use an alternative interface wrapper for request. These wrappers can be useful if you prefer to work with Promises, or if you'd like to use async/await in ES2017.
request-promise (uses Bluebird Promises)
This module is installed via npm:
npm install --save request
npm install --save request-promise
Coming to modifying your code as per documentation:
var requestPromise = require('request-promise');
requestPromise.get({
uri: 'http://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?CMC_PRO_API_KEY=API-KEY-HERE',
json: true
}).then(x1 => {
const BTCdata = x1.data.find(d => d.symbol === 'BTC').quote.USD
.volume_24h; // creating a variable to store a BTC request from API
console.log(BTCdata);
// Saving to database
saveToDatabase(BTCdata);
}).catch(err => {
console.log(err);
});
I am writing a firebase function for the webhook fulfillment of dialogflow chatbot. It keeps generating error that response.send is not a function
const functions = require('firebase-functions');
var request1 = require('request')
exports.webhook = functions.https.onRequest((request, response) => {
console.log("request.body.result.parameters: ", request.body.result.parameters);
let params = request.body.result.parameters;
var options = {
url: `https://islam360api.herokuapp.com/${params.find}`,
json:true
}
request1(options, function(error, response, body){
if(error) response.send({speech: "error in API call"});
else response.send({speech: body.speech});
});
});
Firebase Logs
Problem: this is a problem of shadow variable name, when you are trying to send response using firebase functions response object, in fact you are sending response back on response object of npm request module which is ofcourse not possible
Solution:
just put an underscore or change the spelling and you are ready to go, have a look of code:
(notice change in 5th line from bottom)
const functions = require('firebase-functions');
var request1 = require('request')
exports.webhook = functions.https.onRequest((request, response) => {
console.log("request.body.result.parameters: ", request.body.result.parameters);
let params = request.body.result.parameters;
var options = {
url: `https://islam360api.herokuapp.com/${params.find}`,
json:true
}
request1(options, function(error, _response, body){
if(error) response.send({speech: "error in API call"});
else response.send({speech: body.speech});
});
});
I have an express API:
var bodyParser = require("body-parser");
app.use(bodyParser.json());
app.post("/adapter/mail", function(request, response) {
var body = request.body;
var id = body.id;
var params = {id: id};
Parse.Cloud.run("email", params, {
success: function(e) {
console.log("api: success");
respone.status(200).send("e");
},
error: function(e) {
console.log("api: error: " + JSON.stringify(e));
response.status(500).send(e);
}
});
});
Calling the API calls the Parse Cloud Code:
Parse.Cloud.define("email", function(request, response) {
console.log(JSON.stringify(request, null, 4));
response.success("ok");
});
In the console I see that console.log("api: success"); gets executed correctly, but the API request does not end, it times out despite the successful callback.
When Cloud Code returns response.error("error"); instead of response.success("ok"); the request does not timeout but ends immediately.
Why does the request time out on success?
Looks like you are missing an "s" on your callback
respon"s"e.status(200).send("e");
I have a module under test which uses https to PUT data to a response URL. Before doing so, it makes calls to the AWS SDK. I do not want to stub the calls that AWS SDK makes using https, but I do want to stub the call to https.post that my module under test uses (it's an AWS Lambda unit test if that matters).
Consider the following test code
describe('app', function () {
beforeEach(function () {
this.handler = require('../app').handler;
this.request = sinon.stub(https, 'request');
});
afterEach(function () {
https.request.restore();
});
describe('#handler()', function () {
it('should do something', function (done) {
var request = new PassThrough();
var write = sinon.spy(request, 'write');
this.request.returns(request);
var event = {...};
var context = {
done: function () {
assert(write.withArgs({...}).calledOnce);
done();
}
}
this.handler(event, context);
});
});
});
And my module under test (app.js)
var aws = require("aws-sdk");
var promise = require("promise");
exports.handler = function (event, context) {
var iam = new aws.IAM();
promise.denodeify(iam.getUser.bind(iam))().then(function (result) {
....
sendResponse(...);
}, function (err) {
...
});
};
// I only want to stub the use of https in THIS function, not the use of https by the AWS SDK itself
function sendResponse(event, context, responseStatus, responseData) {
var https = require("https");
var url = require("url");
var parsedUrl = url.parse(event.ResponseURL);
var options = {
...
};
var request = https.request(options, function (response) {
...
context.done();
});
request.on("error", function (error) {
...
context.done();
});
// write data to request body
request.write(...);
request.end();
}
How can I accomplish this?
You could use nock to mock specific HTTP/S requests, rather than function calls.
With nock, you can setup URL and request matchers that will allow requests through that don't match what you've defined.
Eg:
nock('https://www.something.com')
.post('/the-post-path-to-mock')
.reply(200, 'Mocked response!');
This would only intercept POST calls to https://www.something.com/the-post-path-to-mock, responding with a 200, and ignore other requests.
Nock also provides many options for mocking responses or accessing the original request data.
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);
};