My node js app is making multiple http request if there is delay in response of say 20 secs. Below is the sample code for the same.
First I make call to the getAPI function from browser. getApi function calls the getAccessToken API, after receiving the accesstoken I am calling the testApi. Now if there is a delay of 20 secs in response from testApi then getAccessToken Api is getting called again. I don't want to use promise. Can anyone point out what I am missing or doing wrong here?
shttp = require('http-https');
exports.getAPI = function(typeObj, request, response, callback) {
var userConf; //contains info such as port, host, url etc
_this.getAccessToken(function(tokenResponse) {
var tokenInfo = JSON.parse(tokenResponse);
var accessToken = JSON.parse(tokenInfo.response);
accessToken = accessToken.access_token;
if(accessToken) {
_this.testApi(userConf,accessToken,function(sjmResponse) {
callback(sjmResponse);
}
} else {
callback(JSON.stringify({"payLoad":null,"reasonCode":"fail","status":null}));
}
});
};
exports.getAccessToken = function(cb) {
var tokenConf; //contains info such as port, host, url etc
var httpReq = shttp.request(tokenConf, function(res) {
res.setEncoding('utf8');
if (res.statusCode == 200) {
var body = "";
res.on('data', function (result) {
body += result;
});
res.on('end', function (){
cb(JSON.stringify({error: '', response: (body)}));
});
} else {
cb(JSON.stringify({error: 'Failed to get user access token '+res.statusCode, response:''}));
}
});
httpReq.on('error', function(e) {
cb(JSON.stringify({error: 'Failed to get user access token'+e, response:''}));
});
httpReq.end();
};
exports.testApi = function(userConf,accessToken,sjmCallback) {
var userConf; //contains info such as port, host, url etc
var httpSubmitReq = shttp.request(userConf, function(res) {
res.setEncoding('utf8');
if (res.statusCode == 200) {
var body = "";
res.on('data', function (result) {
body += result;
});
res.on('end', function () {
sjmCallback(body);
});
} else {
sjmCallback(JSON.stringify({"payLoad":null,"reasonCode":"fail","status":null}));
}
});
httpSubmitReq.on('error', function(e) {
sjmCallback(JSON.stringify({"payLoad":null,"reasonCode":"fail","status":null}));
});
httpSubmitReq.end();
};
app.get('/testApi', function (req, res) {
var typeObj = {};
typeObj.apiType= 'testApi';
try {
getAPI(JSON.stringify(typeObj), req, res, function(response) {
res.end(response);
});
} catch(err) {
res.end(err);
}
});
Related
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 am trying to use a callback to indicate when all the async workers are complete, but I am getting the dreaded
TypeError: callback is not a function.
I would like to individually process each element in data, and on completion, have queue.drain to send the callback(data) to refresh Data on completion. I have been readying the async documentation, but clearly i am not getting something.
function refreshData(postData, callback) {
var options = {
host: 'www.myhost.com',
port: 443,
path: '/pulldata,
method: 'POST',
headers: {
"Content-Type": "application/json"
}
};
var req = https.request(options, function(res) {
var headers = res.headers
var d = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
d = d + chunk;
});
res.on('end', function() {
if (res.statusCode == '200') {
data = JSON.parse(d);
queue = async.queue(function (task, cb) {
processData(task,cb);
},1);
//this is were the errors are
queue.drain = function() {
callback(data)
};
for(i=0; i<data.length; i++) {
queue.push(data[i],'');
}
} else {
callback(false)
}
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write(postData);
req.end();
}
Any assistance would be greatly appreciated!
Edit, added some pseudo code to demonstrate how refreshData is being used:
Node https.createServer(req,res) {
req.on(){
read userData
}
req.end(){
validateUser(userData, function(callbackData) {
if(callbackData==false) {
//bad user or error with request
res.writeHead(404);
res.end('bye');
} else {
//good user and responses
res.writeHead(200);
res.end(callbackData);
}
})
}
}
function validateUser(userData,callback) {
//do some stuff to validate
if(userData is good) {
//call refreshData if user
refreshData(userData,callback)
} else {
callback(false)
}
}
[EDIT] Added a callback
As given in the documentation you pointed to , change this line
queue.push(data[i],'');
to
queue.push(data[i], function(err){
// handle error
});
Try it here async-queue-callback
i have an application which needs a data.json file in order to draw a d3-graph. However i need to update that file on an onClick-Event:
d3.select("#updatebutton").on("click", function(e) {
try{
$.get('https://localhost:4444/data', function(data) {
});
}
catch (e) {
alert('Error: ' + e);
}
});
Above is the update-Button with the jquery-call. In my app.js File I am using it like this:
app.get('/data', function(req, res, next) {
try{
getJSON();
}
catch(e) {
alert('Error');
}
});
The getJSON()-Function is received Data over an https-Request, processes that data and saves it to data.json:
function getJSON() {
var req = https.get(options, function(response) {
// handle the response
var res_data = '';
response.on('data', function(chunk) {
res_data += chunk;
});
response.on('end', function() {
//process data
// save to file
fs.writeFile(filePath, JSON.stringify(finalJson), function(err) {
if (err)
throw err;
});
});
});
}
However if i click on my updateButton repeatedly after seconds, it seems that data.json is not overwritten but the file gets bigger and bigger, means that data is added to the file instead of overwritten.
What am I doing wrong?
Thanks for help.
Since you use app.get as your route, I guess you are using express.
In your routes definition:
var getData = (function() {
var callbacks = [];
function executeCallbacks(err, data) {
for (var i = 0; i < callbacks.length; i++) {
callbacks[i](err, data);
}
callbacks = [];
}
return function(cb) {
callbacks.push(cb);
if( callbacks.length === 1 ) {
var req = https.get(options, function(response) {
// handle the response
var res_data = '';
response.on('data', function(chunk) {
res_data += chunk;
});
response.once('end', function() {
// process data here
// save to file
fs.writeFile(filePath, JSON.stringify(finalJson), function(err) {
if (err) {
// call error handler
return executeCallbacks(err);
}
executeCallbacks(null, body);
});
});
response.once('error', function() {
return executeCallbacks(err);
});
}
req.end();
}
};
})();
app.get('/data', function(req, res, next) {
getData(function(err, data) {
if(err) {
return next(err);
}
return data;
});
});
In your browser js file:
d3.select("#updatebutton").on("click", function(e) {
$.get( 'https://localhost:4444/data', function(data) {
alert( "success" );
var json = JSON.parse(data);
})
.fail(function() {
alert( "error" );
});
});
I see you use try / catch around callback functions. The callback function fires after the original function completes. So don't use Try / Catch around callback function.
Read: https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/
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);
});
};
var Attendance = require('../../../collections/attendance').Attendance;
var moment = require('moment');
module.exports = function(app) {
app.get('/api/trackmyclass/attendance', function(req, res) {
var data = req.body;
data['user'] = req.user;
Attendance.getByUser(data, function(err, d) {
if (err) {
console.log('This is the err' + err.message);
res.json(err, 400);
} else {
var job = d['attendance'];
if (typeof job != undefined) {
res.json(job);
console.log('This is it' + job['status']);
} else
res.json('No data Present', 200);
}
});
});
app.post('/api/trackmyclass/attendance', function(req, res) {
var data = req.body;
data['user'] = req.user;
Attendance.create(data, function(err, d) {
if (err) {
console.log('This is the err' + err.message);
res.json(err, 400);
} else {
var attendance = d['attendance'];
if (typeof job != undefined) {
console.log('Attendance record created' + attendance);
res.json(attendance);
} else
res.json('No data Present', 200);
}
});
});
}
This is the api code I to which I need to make the GET and POST request. But I have no idea how to do it.
It looks like your code is using express which would normally be good for building and API for your app. However to make a simple request to a third party api and staying in node.js why not try the request module which is great. https://www.npmjs.org/package/request
Your example does not show what the path of the request is or if you need any additinal headers etc but here is a simple example of a GET request using request.
var request = require('request');
function makeCall (callback) {
// here we make a call using request module
request.get(
{ uri: 'THEPATHAND ENDPOINT YOU REQUEST,
json: true,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded',
}
},
function (error, res, object) {
if (error) { return callback(error); }
if (res.statusCode != 200 ) {
return callback('statusCode');
}
callback(null, object);
}
);
}
or jquery .ajax from a front end client direcct to your path
$.ajax({
url: "pathtoyourdata",
type: "GET",
})
.done(function (data) {
//stuff with your data
});