I would like to use two IBM Watson services and combine the responses from both in one variable and return it as a callback. I couldn't figure out how to get response1 value outside the http request to combine it with response2 from the other IBM Watson service.
I tried the below code and it didn't work. I read that I can use promises, but I'm pretty new to this, and couldn't figure out how to do this.
Can anyone help please?
const AWS = require('aws-sdk');
var http = require('https');
exports.handler = (event, context, callback) => {
var text = JSON.stringify(event.text);
var options = {
method: process.env.method,
hostname: process.env.watson_hostname,
port: null,
path: process.env.path,
headers: {
'content-type': process.env.content_type,
authorization: process.env.authorization,
'cache-control': process.env.cache_control,
'X-Watson-Learning-Opt-Out': 'true'
}
};
var req = http.request(options, function (res) {
var chunks = "";
res.on("data", function (chunk) {
chunks+ = chunk.toString();;
});
res.on("end", function () {
var response1 = (chunks);
//////////////here I need to get reponse2
var response2 = IBM2();
var bothResponses = response1 + response2
callback(null,bothResponses)
});
})
req.write(text);
req.end()
function IBM2(){
var text = JSON.stringify(event.text);
var options = {
method: process.env.method2,
hostname: process.env.watson_hostname2,
port: null,
path: process.env.path2,
headers: {
'content-type': process.env.content_type2,
authorization: process.env.authorization2,
'cache-control': process.env.cache_control,
'X-Watson-Learning-Opt-Out': 'true'
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var response2 = JSON.parse(Buffer.concat(chunks));
return(response2)
}
Return a promise from your IBM2 function and handle using async await in the calling function. Notice the async keyword before on end callback.
I have tried to add Promise to your existing flow:
const AWS = require('aws-sdk');
var http = require('https');
exports.handler = (event, context, callback) => {
var text = JSON.stringify(event.text);
var options = {
method: process.env.method,
hostname: process.env.watson_hostname,
port: null,
path: process.env.path,
headers: {
'content-type': process.env.content_type,
authorization: process.env.authorization,
'cache-control': process.env.cache_control,
'X-Watson-Learning-Opt-Out': 'true'
}
};
var req = http.request(options, function (res) {
var chunks = "";
res.on("data", function (chunk) {
chunks += chunk.toString();;
});
res.on("end", async function () {
var response1 = (chunks);
//////////////here I need to get reponse2
var response2 = await IBM2();
// validate response2 (in case IBM2 throws error)
var bothResponses = response1 + response2;
callback(null,bothResponses)
});
});
req.write(text);
req.end();
function IBM2(){
return new Promise((resolve, reject) =>{
var text = JSON.stringify(event.text);
var options = {
method: process.env.method2,
hostname: process.env.watson_hostname2,
port: null,
path: process.env.path2,
headers: {
'content-type': process.env.content_type2,
authorization: process.env.authorization2,
'cache-control': process.env.cache_control,
'X-Watson-Learning-Opt-Out': 'true'
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var response2 = JSON.parse(Buffer.concat(chunks));
resolve(response2)
});
res.on("error", function (err) {
reject(err);
});
})
});
}
};
Before making any changes to your code, I would suggest you go thru these topics first.
For reference, do take a look into the concept of promises and async-await
Promiese
Async/Await
Dont know if you have other errors, but it looks like youre not waiting for response2 to finish, maybe something like
const response2 = await IBM2():
or if you want to use promises maybe something like:
res.on('end', function () {
var response2 = IBM2().then(
val => {
var bothResponses = response1 + val;
callback(null, bothResponses);
},
reject => {
/* handle rejection here */
},
);
});
Related
I'm trying to call an API inside a for loop using Nodejs,when the code is executed only the last element is called by the API:
the code :
var array=[12,124,852,256,5677,256,5679,2546,567,28,574]
for(var i=0;i<array.length;i=i++){
var b = array.splice(i,3);
const parameters1 = {
Ids: b.toString(),
limit: 45,
}
const get_request_args1 = querystring.stringify(parameters1);
const options1 = {
method: 'GET',
host: "host",
port: '443',
path: path + '?' + get_request_args1,
headers: {
'Accept': 'application/json',
'authorization': `Bearer ${token}`,
'Accept-Encoding': 'identity',
}
}
var req = http.request(options1, (res) => {
context.log("API CALL...",i);
var body = "";
var pages = 0;
var offset = [];
var limit = 100000;
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
const obj = JSON.parse(body);
//context.log('total pages 3 :', pages);
context.log('total :', obj.total);
context.res = { body: offset };
context.done();
});
}).on("error", (error) => {
context.log('ERROR :', error);
context.res = {
status: 500,
body: error
};
context.done();
});
}
when this code is executed only the last element in the array executed by the API, what I'm looking for is executing the api for each iteration of the for loop, any helps please ?
Not sure how your full function looks like, but you should build your function as fully structured as async-await.
And also you could use map function instead of for.
const yourFunction = async () => {
try {
const array = [12,124,852,256,5677,256,5679,2546,567,28,574];
const requests = array.map(async (item) => {
...
var req = await http.request(async options1, (res) => {
context.log("API CALL...",i);
...
});
await Promise.all(requests);
...
} catch (err) {
console.error(err);
}
}
I am calling an api of sending OTP from my nodejs app. I need to send the response of that OTP Api to the angular app.
my api service on angular look like this:
sendOtp(params): Observable<any> {
return this.apiService.post("/user/send-otp", params)
}
my router on express app look like this
this.router.post("/user/send-otp", userController.sendOtpMessage);
and the code inside userController look like this.
static sendOtpMessage(req, res ,next) {
const phone = req.body.phone;
var http = require("https");
var options = {
"method": "GET",
"hostname": "api.msg91.com",
"port": null,
"path": `/api/v5/otp?mobile=${phone}`,
"headers": {
"content-type": "application/json"
}
};
var callOtpApi = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
// I need to send this data in response to my angular app ==>> body.toString()
});
});
callOtpApi.write();
callOtpApi.end();
}
OTP Api ref document: https://docs.msg91.com/p/tf9GTextN/e/B1NUt3C8MY/MSG91
It seems that the code above is missing the res.send() to return the data from server. Could you please try with this?
static sendOtpMessage(req, res ,next) {
const serverRes = res;
// Rest of your code
...
var callOtpApi = http.request(options, function (res) {
// Rest of your code
...
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
// Return data to client
serverRes.send(body.toString());
});
// Rest of your code
...
});
}
You can call the msg91 api using axios
const axios = require('axios');
async function sendOtpTOUser(phone) {
const template = "template _id";
const apiKey = "api_key";
const sendotp = "https://api.msg91.com/api/v5/otp?template_id="+template+"&mobile="+phone+"&authkey="+apiKey;
let request_options1 = {
method: 'get',
url: sendotp
};
let otpResponse = await axios(request_options1);
console.log(otpResponse.data)
return otpResponse.data;
}
it will return the object as
{ request_id: '3166686e7867313634383535', type: 'success' }
I want to return the value that has been declared in the first Function CreateTag and using it as variable in the second Function CreateStream, but it won't work..
I'm working with nodejs Express.
I try to use RETURN but it won't work..
I have tried it in differance ways, but still not work..
Can you someone help me, please?
'use strict';
var express = require('express');
var router = express.Router();
/* GET home page. */
//Function 1: createTag
var createTag = function hi (TanentValue) {
var https = require('https');
var data = JSON.stringify({
name: TanentValue,
schemaPath: "Tag"
});
var options = {
hostname: 'qlik_dev.be',
path: '/meteor/qrs/tag?xrfkey=1234567890123456',
method: 'POST',
headers: {
'x-qlik-xrfkey': '1234567890123456',
'hdr-usr': 'gak\\gaka',
'Content-Type': 'application/json'
},
};
var req = https.request(options, (res) => {
//console.log(res)
res.on('data', (d) => {
console.log("hi tag")
var getResult = "GaLvAnI"; // ----> return this and use it into the function createStream
return getResult;
})
})
;
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
}
//Function 2: createStream
var createStream = function (TanentValue) {
var https = require('https');
var galvani = hi(); // --------> here I made a variable to call return value
var data = JSON.stringify({
name: TanentValue,
});
var options = {
hostname: 'qlik_dev.be',
path: '/meteor/qrs/stream?xrfkey=1234567890123456',
method: 'POST',
headers: {
'x-qlik-xrfkey': '1234567890123456',
'hdr-usr': 'gak\\gaka',
'Content-Type': 'application/json'
},
};
var req = https.request(options, (res) => {
res.on('data', (d) => {
console.log(galvani); // -----> use the variable here
})
})
;
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
}
//homepage
router.get('/', function (req, res) {
res.render('index', { title: 'MCS Test' });
});
//create
router.post('/create', function (req, res) {
//create tag
console.log('POST / Call Create Tag');
createTag(req.body.TanentValue);
//create stream
console.log('POST / Call Create Stream');
createStream(req.body.TanentValue);
res.send('Stream and Tag has been created');
});
module.exports = router;
you can not directly return value from async function. you have to use promise. something like this:
'use strict';
var express = require('express');
var router = express.Router();
/* GET home page. */
//Function 1: createTag
var createTag = function (TanentValue) { // function should be anonymouse
return new Promise((resolve, reject) => {
var https = require('https');
var data = JSON.stringify({
name: TanentValue,
schemaPath: "Tag"
});
var options = {
hostname: 'qlik_dev.be',
path: '/meteor/qrs/tag?xrfkey=1234567890123456',
method: 'POST',
headers: {
'x-qlik-xrfkey': '1234567890123456',
'hdr-usr': 'gak\\gaka',
'Content-Type': 'application/json'
},
};
var req = https.request(options, (res) => {
//console.log(res)
res.on('data', (d) => {
console.log("hi tag")
var getResult = "GaLvAnI"; // ----> return this and use it into the function createStream
resolve(getResult); // success call
})
})
;
req.on('error', (error) => {
reject(error); // error call
});
req.write(data);
req.end();
});
}
//Function 2: createStream
var createStream = function (TanentValue) {
createTag().then((val) => {
var https = require('https');
var galvani = val; // use that value from sucess call
var data = JSON.stringify({
name: TanentValue,
});
var options = {
hostname: 'qlik_dev.be',
path: '/meteor/qrs/stream?xrfkey=1234567890123456',
method: 'POST',
headers: {
'x-qlik-xrfkey': '1234567890123456',
'hdr-usr': 'gak\\gaka',
'Content-Type': 'application/json'
},
};
var req = https.request(options, (res) => {
res.on('data', (d) => {
console.log(galvani); // -----> use the variable here
})
})
;
req.on('error', (error) => {
console.error(error)
});
req.write(data);
req.end();
})
.catch((error) => {
// handle error from createTag function here
});
}
//homepage
router.get('/', function (req, res) {
res.render('index', { title: 'MCS Test' });
});
//create
router.post('/create', function (req, res) {
//create tag
console.log('POST / Call Create Tag');
createTag(req.body.TanentValue);
//create stream
console.log('POST / Call Create Stream');
createStream(req.body.TanentValue);
res.send('Stream and Tag has been created');
});
module.exports = router;
You can solve it using just callback function or the promise.
Using callbacks.
'use strict';
var express = require('express');
var router = express.Router();
/* GET home page. */
//Function 1: createTag
var createTag = (TanentValue, callback) => {
var https = require('https');
var data = JSON.stringify({
name: TanentValue,
schemaPath: "Tag"
});
var options = {
hostname: 'qlik_dev.be',
path: '/meteor/qrs/tag?xrfkey=1234567890123456',
method: 'POST',
headers: {
'x-qlik-xrfkey': '1234567890123456',
'hdr-usr': 'gak\\gaka',
'Content-Type': 'application/json'
},
};
var req = https.request(options, (res) => {
res.on('data', (d) => {
console.log("hi tag")
var getResult = "GaLvAnI"; // ----> return this and use it into the function createStream
callback(false, getResult);
})
});
req.on('error', (error) => {
//console.error(error)
callback(true, error);
});
req.write(data);
req.end();
}
//Function 2: createStream
var createStream = (TanentValue, callback) => {
var https = require('https');
var data = JSON.stringify({
name: TanentValue,
});
var options = {
hostname: 'qlik_dev.be',
path: '/meteor/qrs/stream?xrfkey=1234567890123456',
method: 'POST',
headers: {
'x-qlik-xrfkey': '1234567890123456',
'hdr-usr': 'gak\\gaka',
'Content-Type': 'application/json'
},
};
createTag(TanentValue, (is_error, galvani) => {
if(err || !data){
// do error handling...
callback(true); // true for there was an error
}else{
var req = https.request(options, (res) => {
res.on('data', (d) => {
callback(false);
console.log(galvani); // -----> use the variable here
})
});
req.on('error', (error) => {
callback(true);
console.error(error)
});
req.write(data);
req.end();
}
})
}
//homepage
router.get('/', function (req, res) {
res.render('index', { title: 'MCS Test' });
});
//create
router.post('/create', function (req, res) {
/*
// Since the stream seems to depend on the tag created,
// you don't need to call createTag explicitly because
// it is always/already called from createStream.
//create tag
console.log('POST / Call Create Tag');
createTag(req.body.TanentValue, function(is_error, data){
if(!is_error){
// do something
}else{
// do error handling
console.error(error);
res.send('Tag could not be created, please try later again..');
}
});
*/
//create stream
console.log('POST / Call Create Stream');
createStream(req.body.TanentValue, is_error => {
if(!is_error){
res.send('Stream and Tag has been created');
}else{
res.send('Stream could not be created, please try later again..');
}
});
});
module.exports = router;
Using Promise
'use strict';
var express = require('express');
var router = express.Router();
/* GET home page. */
//Function 1: createTag
var createTag = TanentValue => {
var https = require('https');
var data = JSON.stringify({
name: TanentValue,
schemaPath: "Tag"
});
var options = {
hostname: 'qlik_dev.be',
path: '/meteor/qrs/tag?xrfkey=1234567890123456',
method: 'POST',
headers: {
'x-qlik-xrfkey': '1234567890123456',
'hdr-usr': 'gak\\gaka',
'Content-Type': 'application/json'
},
};
return new Promise((resolve, reject) => {
var req = https.request(options, (res) => {
res.on('data', (d) => {
console.log("hi tag")
var getResult = "GaLvAnI"; // ----> return this and use it into the function createStream
resolve(getResult);
})
});
req.on('error', (error) => {
//console.error(error)
reject(error);
});
req.write(data);
req.end();
})
}
//Function 2: createStream
var createStream = TanentValue => {
var https = require('https');
var data = JSON.stringify({
name: TanentValue,
});
var options = {
hostname: 'qlik_dev.be',
path: '/meteor/qrs/stream?xrfkey=1234567890123456',
method: 'POST',
headers: {
'x-qlik-xrfkey': '1234567890123456',
'hdr-usr': 'gak\\gaka',
'Content-Type': 'application/json'
},
};
createTag(TanentValue).then( galvani => {
return new Promise((resolve, reject) => {
var req = https.request(options, (res) => {
res.on('data', (d) => {
console.log(galvani); // -----> use the variable here
resolve(d);
})
});
req.on('error', (error) => {
console.error(error)
reject({ msg: 'request error while creating the stream', error: error})
});
req.write(data);
req.end();
})
}).catch( error => {
// do error handling...
reject({msg: 'Error while creating a tag', error: error}); // true for there was an error
});
}
//homepage
router.get('/', function (req, res) {
res.render('index', { title: 'MCS Test' });
});
//create
router.post('/create', function (req, res) {
/*
// Since the stream seems to depend on the tag created,
// you don't need to call createTag explicitly because
// it is always/already called from createStream.
//create tag
console.log('POST / Call Create Tag');
createTag(req.body.TanentValue).then( data => {
// do something
}).catch( error => {
// do error handling
});
*/
//create stream
console.log('POST / Call Create Stream');
createStream(req.body.TanentValue).then( data => {
res.send('Stream and Tag has been created');
}).catch(error => {
// 'Stream could not be created, please try later again..'
res.send(error.msg);
});
});
module.exports = router;
Very handfull!! thank you it works!
But while passing the data (Json) from function 1 to function 2 with Promise, the data (json) is undefine in function 2. If I pass a data (String) from function 1 to function 2 than it works..
Why does it give me 'undefine' when it is a json?
//var id;
var req = https.request(options, (res) => {
//console.log(res)
res.setEncoding('utf8');
res.on('data', function (data) {
var json = JSON.parse(data);
var TagId = JSON.stringify(json[0]);
console.log("2 hi getTap");
console.log(TagId); // -------> here it works well
resolve(TagId);
});
});
var req = https.request(options, (res) => {
res.on('data', (d) => {
console.log("3 hi createStream");
console.log(galvani); // -------> here it doesn't work.. it gives me undefine
})
});
here a printscreen of response
I am calling a javascript function , which in turn calls a web service;The response of this service is used to call another function which also calls a service. At end of both services we set session attributes. This code gives no errors, but the callback gets called before the service has returned data. The main motive of this code is to set the session attributes before return of flow from this code, when the callback gets called before the service has returned values the session attributes are not set and the requirement of the code is not fulfilled.
'use strict';
function close(sessionAttributes, fulfillmentState, message) {
return {
sessionAttributes,
dialogAction: {
type: 'Close',
fulfillmentState,
message : 'For security purpose answer these questions '
},
};
}
function getSecurityQuestions(intentRequest, context, post_options, callback){
const sessionAttributes = intentRequest.sessionAttributes || {};
var policynumber = sessionAttributes.policynumber;
var interactionID = sessionAttributes.interactionID;
var body = "";
var body2;
const http = require('https');
const promise = new Promise((resolve, reject) => {
const post_data = JSON.stringify({"Purpose":"SecurityQuestions", "InteractionID":interactionID, "SearchStringAcctNum":policynumber});
//ignores SSL
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var post_request = http.request(post_options, function(res) {
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
context.done(body);
resolve(body);
});
res.on('error', function(e) {
reject(Error(e.message));
context.fail('error:' + e.message);
});
});
// post the data
post_request.write(post_data);
post_request.end();
});
callback( promise.then((body) => {
body2 = JSON.parse(body);
sessionAttributes.question1 = body2.SecurityDetails[0].Question;
close(sessionAttributes, 'Fulfilled');
}, (error) => {
console.log(error.message);
})
);
}
function getInteraction(intentRequest, context, callback) {
const slots = intentRequest.currentIntent.slots;
var policynumber = "PA"+slots.PolicyNumber;
var questionOne = slots.questionOne;
var questionTwo = slots.questionTwo;
const sessionAttributes = intentRequest.sessionAttributes || {};
console.log("policy number : "+policynumber + "question 1 : "+questionOne + "question 2 : "+questionTwo);
sessionAttributes.policynumber = policynumber;
var body = "";
var body2;
// An object of options to indicate where to post to
var post_options = {
host: 'example.com',
protocol: 'https:',
port: '3000',
path: '/hiddenPath',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
const http = require('https');
const promise = new Promise((resolve, reject) => {
const post_data = JSON.stringify({"Purpose":"CreateInteraction"});
//ignores SSL
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var post_request = http.request(post_options, function(res) {
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
context.done(body);
resolve(body);
});
res.on('error', function(e) {
console.log("rejected here");
reject(Error(e.message));
context.fail('error:' + e.message);
});
});
// post the data
post_request.write(post_data);
post_request.end();
});
callback( promise.then((body) => {
body2 = JSON.parse(body);
console.log("interaction ID : "+body2.InteractionID);
sessionAttributes.interactionID = body2.InteractionID;
getSecurityQuestions(intentRequest, context, post_options, callback);
}, (error) => {
console.log('Promise rejected.');
console.log(error.message);
}));
}
// --------------- Intents -----------------------
/**
* Called when the user specifies an intent for this skill.
*/
function dispatch(intentRequest, context, callback) {
const intentName = intentRequest.currentIntent.name;
if (intentName === 'currIntent') {
return getInteraction(intentRequest, context, callback);
}
throw new Error(`Intent with name ${intentName} not supported`);
}
// --------------- Main handler -----------------------
function loggingCallback(response, originalCallback) {
console.log("logging callback called......");
originalCallback(null, response);
}
exports.handler = (event, context, callback) => {
try {
dispatch(event, context, (response) => loggingCallback(response, callback));
} catch (err) {
callback(err);
}
};
You should resolve your promise only after the request ends.. Have updated your sample below. Hope it helps. Also, you were sending an invalid object as your post body. Fixed that as well.
function getValue(context, post_options, callback) {
var body = "";
var body2;
const http = require('http');
const promise = new Promise((resolve, reject) => {
// INVALID OBJECT
//const post_data = JSON.stringify({"something"});
const post_data = JSON.stringify({
something: "something"
});
//ignores SSL
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var post_request = http.request(post_options, function(res) {
res.on('data', function(chunk) {
body += chunk;
console.log("inside " + JSON.stringify(body));
// DONT RESOLVE HERE, REQUEST IS NOT COMPLETE
//resolve(body);
});
res.on('end', function() {
context.done(body);
//RESOLVE HERE INSTEAD
resolve(body);
});
res.on('error', function(e) {
reject(Error(e.message));
context.fail('error:' + e.message);
});
});
// post the data
post_request.write(post_data);
post_request.end();
});
promise.then((body) => {
console.log("response data " + JSON.stringify(body));
body2 = JSON.parse(body);
callback(delegate(sessionAttributes, intentRequest.currentIntent.slots));
}, (error) => {
console.log('Promise rejected.');
console.log(error.message);
});
}
I'm banging my head for not learning from the basics and just jumping in.
I'm building an API that returns the SSL Certificate status of a domain.
It's working fine on console.log but the JSON output is empty, obviously because the exports get executed before the https request ends.
How do I incorporate the exports in response.on(end) function?
Thanks a lot!
function getSSL(domain) {
var options = {
host: 'www.'+domain+'.com',
method: 'get',
path: '/'
};
var isAuth = false;
callback = function(response) {
response.on('data', function () {
isAuth = response.socket.authorized;
});
response.on('end', function () {
console.log(isAuth);
});
}
var req = https.request(options, callback).end();
}
exports.findByDomain = function (req, response) {
var id = req.params.id;
sslCheck = getSSL(id);
response.send(sslCheck);
};
Yes, the response.send(sslCheck); gets executed before getSSL(id); has a chance to finish. You need to send in a callback so it can be executed after getSSL(id); finishes:
function getSSL(domain, callback) {
var options = {
host: 'www.'+domain+'.com',
method: 'get',
path: '/'
};
var isAuth = false;
var httpCallback = function(response) {
response.on('data', function () {
isAuth = response.socket.authorized;
});
response.on('end', function () {
console.log(isAuth);
callback(isAuth);
});
}
var req = https.request(options, httpCallback).end();
}
exports.findByDomain = function (req, response) {
var id = req.params.id;
getSSL(id, function(sslCheck) {
response.send(sslCheck);
});
};