NodeJS function returns before intended - node.js

I have a function that loops and makes some API calls:
sendText(clientArr){
clientArr.forEach(function (textObject, index) {
var myRequest = {
body: textObject.messageContent,
to: { phoneNumber: textObject.phoneNumber },
rules: ['sms']
};
var options = {
method: 'POST',
url: comapiUrl,
headers:
{
'cache-control': 'no-cache',
'content-type': 'application/json',
'accept': 'application/json',
authorization: 'Bearer ' + yourComapiAccessToken
},
body: myRequest,
json: true
};
console.log('');
console.log('Calling Comapi...');
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log("HTTP status code returned: " + response.statusCode);
// Check status
if (response.statusCode == 201)
{
// All ok
console.log('SMS message successfully sent via Comapi "One" API');
}
else
{
// Something went wrong
console.log('Something went wrong!');
}
console.log(body);
return response
});
})
};
This function got called from here:
function callAPI(req, res, apiMethod) {
let params = {};
params = req.params;
params.headers = req.headers;
if (req.method.toLowerCase() != 'get') {
params.post = req.body;
}
params.query = req.query;
params.middlewareStorage = req.middlewareStorage;
apiMethod(params)
.success(function (result) {
res.send(result);
})
.failure(function (error) {
console.logger.error(error);
if (!(Object.prototype.toString.call(error) === '[object Object]')) {
error = {success: false, error: error};
}
console.logger.error(error);
res.status(500).send(error);
});
}
router:
router.post('/sendText', function (req,res) {
callAPI(req, res, fn.bind(apiObj, 'sendText'));
});
What I am getting in response is:
POST /clients/sendText 500 320.615 ms - 1514
2018-01-04 02:03:38.887 DEBUG app - HTTP status code returned: 201
It returns with 500 error:
Cannot read property 'success' of undefined\n at callAPI (
before I intended it to return.
How do I fix this?

The sendText method is returning nothing and thus undefined. And hence that does not have success or failure method. However, even if it returns a valid response. The response should have success and failure method.
A better way here will to use promises. You can return promise from api method and change the callAPI method to use the promise interface.
sendText method (using request-promise instead of request)
sendText(clientArr) {
return Promise.all(clientArr.map(function (textObject, index) {
var myRequest = {
body: textObject.messageContent,
to: { phoneNumber: textObject.phoneNumber },
rules: ['sms']
};
var options = {
method: 'POST',
url: comapiUrl,
headers:
{
'cache-control': 'no-cache',
'content-type': 'application/json',
'accept': 'application/json',
authorization: 'Bearer ' + yourComapiAccessToken
},
body: myRequest,
json: true,
resolveWithFullResponse: true
};
console.log('');
console.log('Calling Comapi...');
return request(options)
.then(function (response) {
if (error) throw new Error(error);
console.log("HTTP status code returned: " + response.statusCode);
// Check status
if (response.statusCode == 201)
{
// All ok
console.log('SMS message successfully sent via Comapi "One" API');
}
else
{
// Something went wrong
console.log('Something went wrong!');
}
console.log(body);
return response
});
})
};
callApi
function callAPI(req, res, apiMethod) {
let params = {};
params = req.params;
params.headers = req.headers;
if (req.method.toLowerCase() != 'get') {
params.post = req.body;
}
params.query = req.query;
params.middlewareStorage = req.middlewareStorage;
apiMethod(params)
.then(function (result) {
res.send(result);
})
.catch(function (error) {
console.logger.error(error);
if (!(Object.prototype.toString.call(error) === '[object Object]')) {
error = {success: false, error: error};
}
console.logger.error(error);
res.status(500).send(error);
});
}

Related

How can i use promise method in node

I was trying out the promise function for the REST API instead of using axios method. so I can wait for the result and if there is any error. can anyone help me change this code to promise in node.js so I can do a fetch using promise method. thank you
this is my code
const email = "xxx#xxxx.com"
function isUserExists(email, kc_accessToken) {
let url = `${path}/users?email=${email}`;
return axios_instance.get(url,
{
headers: {
"content-type": "application/json",
"authorization": `Bearer ${kc_accessToken}`
}
}).then(function (response) {
if (response.data.length > 0) {
return true;
} else {
return false;
}
})
.catch(function (error) {
console.log("some error occured");
});
}
Method call
http.createServer(function Test() {
getAccessToken().then(function (response) {
kc_accessToken = response.data.access_token;
IsUserExists(email, kc_accessToken).then((resp) => {
console.log(resp)
if(resp) {
console.log("Do Not Create")
} else if (!resp) {
console.log("Creat a new User")
}
})
}).catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});;
}).listen(8081);
I think you need something like that :
const email = "xxx#xxxx.com"
const request = require('request');
function isUserExists(email, kc_accessToken) {
let url = `${path}/users?email=${email}`;
return new Promise(function(resolve, reject){
request({
url: url,
headers: {
"content-type": "application/json",
"authorization": `Bearer ${kc_accessToken}`
}
}, function (error, response, body) {
if (error) {
console.log("some error occured");
}
if (response.data.length > 0) {
return resolve();
}
return reject();
});
});
}

Invalid Access Token in AWS Alexa Skill

Here is my code which I used for fetching the profile details using alexa skills but getting 401 issue along with below error
const GetMyEmailIntentHandler = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
handlerInput.requestEnvelope.request.intent.name === 'GetMyEmailIntent'
);
},
async handle(handlerInput) {
var apiaccessToken = handlerInput.requestEnvelope.context.System.apiAaccessToken;
var options = {
host : baseURL,
path : '/v2/accounts/~current/settings/Profile.email',
Accept: 'application/json',
method : 'GET',
headers:{
auth: 'Bearer ' + apiaccessToken
}
}
// making the https get call
var getReq = https.request(options, function(res) {
res.on('data', function(data) {
});
});
//end the request
getReq.end();
getReq.on('error', function(err){
});
return new Promise(resolve => {
getEmail(apiaccessToken => {
var speechText = 'Your accessToken fetched successfully';
resolve(
handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.getResponse()
);
});
});
}
};
The error message that results is a 401 error that states that it's unable to determine the domain name. It also says I have an invalid token. However, I have provided the auth bearer token as a header inside the options object. I'm doing string concatenation to appear Bearer to the api token that comes in on the handlerInput.
2019-07-24T13:12:17.200Z c3b8254b-e773-43db-8a96-0ff0aeea1f5e Error handled: Unable to determine the domain name
2019-07-24T13:12:17.418Z c3b8254b-e773-43db-8a96-0ff0aeea1f5e
status code:============= 401
2019-07-24T13:12:17.419Z c3b8254b-e773-43db-8a96-0ff0aeea1f5e
INSIDE res.on:============= { code: 'ACCESS_DENIED', message: 'Invalid token' }
END RequestId: c3b8254b-e773-43db-8a96-0ff0aeea1f5e
I was getting the same. The only change I made is fetching the API endpoint from Context rather than hardcoding it.Below is the code that worked for me.
var profileAccessToken = 'Bearer ' + this.event.context.System.apiAccessToken;
var profileApiEndpoint = this.event.context.System.apiEndpoint;
const options = {
Host: profileApiEndpoint,
Accept: 'application/json',
Authorization: profileAccessToken
};
console.log(options);
var requestURLProfileEmail = profileApiEndpoint + "/v2/accounts/~current/settings/Profile.email";
console.log(requestURLProfile);
https.get(requestURLProfileEmail, options, (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
console.log('Response profile info request-->' + data);
});
}).on("error", (err) => {
console.log(err);
this.emit(":tell", "There was an error processing your request.Please try again.");
});

How to make something like remote method on loop-back middleware?

In fallowing code i want to make something like remote method on middleware in loopback to post values to calculate for example:
in app :
submitForm() {
let headers = new Headers(
{
'Content-Type': 'application/json',
'Accept': 'application/json'
});
let options = new RequestOptions({ headers: headers });
let data = JSON.stringify({
Value1: this.form.value1,
Value2: this.form.value2,
Value3: this.form.value3
});
console.log(data);
let url = 'http://localhost:3000/calculate';
console.log(url);
return new Promise((resolve, reject) => {
this.http.post(url, data, options)
.toPromise()
.then((response) => {
console.log('API Response : ', response.status);
resolve(response.json());
})
.catch((error) => {
console.error('API Error : ', error.status);
console.error('API Error : ', JSON.stringify(error));
reject(error.json());
});
});
}
and in remote method or anything like that, I used such this code but totally fails:
module.exports = function () {
accepts: [{arg: 'val1', type: 'number'},{arg: 'val2', type: 'number'}],
returns: {arg: val1+val2, type: 'number'},
http: {path: '/calculate', verb: 'get'}
});
};
Example remote method that I used correctly
module.exports = function (TeamRole) {
TeamRole.getUsers = function (id, cb) {
TeamRole.find({
where: {
teamId: id
}
}, function (err, users) {
cb(null, users);
});
};
TeamRole.remoteMethod('getUsers', {
accepts: {
arg: "id",
type: "string",
required: true
},
returns: {
arg: 'users',
type: 'Array'
},
http: {
path: '/:id/users',
verb: 'get'
}
});
}
As above example you can define remote method correctly to achieve you task.
cheers.
This is my solution for my problem:
As you can see there is no parameters shown on URL and i think this may be secure I'm not expert one but I guess help to you:
module.exports = function(server) {
const https = require('https');
var request = require('request');
return function verification(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Access-Control-Allow-Credentials', true);
var request;
var response;
var body = '';
// When a chunk of data arrives.
req.on('data', function (chunk) {
// Append it.
body += chunk;
});
// When finished with data.
req.on('end', function () {
// Show what just arrived if POST.
if (req.method === 'POST') {
console.log(body);
}
// Which method?
switch (req.method) {
case 'GET':
Verify url and respond with appropriate data.
handleGet(req, res);
Response has already been sent.
response = '';
break;
case 'POST':
// Verify JSON request and respond with stringified JSON response.
response = handlePost(body);
break;
default:
response = JSON.stringify({ 'error': 'Not A POST' });
break;
}
// Send the response if not empty.
if (response.length !== 0) {
res.write(response);
res.end();
}
// Paranoid clear of the 'body'. Seems to work without
// this, but I don't trust it...
body = '';
});
// If error.
req.on('error', function (err) {
res.write(JSON.stringify({ 'error': err.message }));
res.end();
});
//
};
function handlePost(body) {
var response = '';
var obj = JSON.parse(body);
// Error if no 'fcn' property.
if (obj['fcn'] === 'undefined') {
return JSON.stringify({ 'error': 'Request method missing' });
}
// Which function.
switch (obj['fcn']) {
// Calculate() requres 3 arguments.
case 'verification':
// Error if no arguments.
if ((obj['arg'] === 'undefined') || (obj['arg'].length !== 3)) {
response = JSON.stringify({ 'error': 'Arguments missing' });
break;
}
// Return with response from method.
response = verification(obj['arg']);
break;
default:
response = JSON.stringify({ 'error': 'Unknown function' });
break;
}
return response;
};
function verification(arg) {
var n1 = Number(arg[0]);
var n2 = Number(arg[1]);
var n3 = Number(arg[2]);
var result;
// Addem up.
result = n1 + n2 + n3;
// Return with JSON string.
return JSON.stringify({ 'result': result });
};
};

Node.js request inside express server doesn't seem to work in parallel

I've a simple express server responding to one post request:
app.post('/reportFiles', getReportLink);
The server is going to make a post request on another server then save the result into a json file.
But it seems to be not working when i make multiple request. If I call 2 times my express server and the request to the other server are slow, I'll get the result of my first request but never my second (request are the same, just called 2 times).
Here is my code for the function getReportLink:
function getReportLink(req,res){
var params = req.body;
// Send 200 response -> Doing the job in background
respond(res,200,'OK');
var json;
var requestName = params.requestName;
var sessionId = params.sessionId;
var startDate = params.startDate;
var endDate = params.endDate;
var customerId = params.customerId;
var uaid = params.uaid;
var jsonFileName = requestName+'_'+customerId+'_'+uaid+'_'+unix()+'.json';
var platformUrl = require(current_path+path.sep+'platform').getPlatformUrl(config.environment);
async.series([
// Call getrequestName on spring-ws
function(callback){
var requestBody = {sessionId:sessionId,asynch:false,startDate:startDate,endDate:endDate,formatedForTimezone:true,timeZoneOffset:timeZoneOffset};
var reportParams = params;
_.each(_.keys(reportParams), function (key) {
if(key==='reportType' && reportParams[key]<=0){
// We don't add it
}else{
requestBody[key] = reportParams[key];
}
});
logger.debug(jsonFileName);
logger.debug(requestBody);
request({
uri: platformUrl+'get'+reportParams.requestName,
method: 'POST',
json: true,
timeout: 600000,
headers: {'content-type': 'application/json'},
body: requestBody},
function(error, response, body) {
if(!_.isUndefined(response)){
logger.debug(jsonFileName);
logger.debug('Response: '+ response.statusCode);
}
if (error || response.statusCode == 500) {
logger.debug(jsonFileName);
logger.error(error);
logger.debug('Received:'+JSON.stringify(body));
if(!_.isUndefined(returnUrl) && returnUrl){
return respond(res,500, 'Error when getting ressource');
} else {
return logger.error('Error when getting ressource');
}
} else {
json = body;
if( _.isUndefined(json) || _.isNull(json)){
logger.debug(jsonFileName);
logger.debug('Received:'+JSON.stringify(json));
if(!_.isUndefined(returnUrl) && returnUrl){
return respond(res,500, 'Error when getting ressource - not a json object');
} else {
return logger.error('Error when getting ressource - not a json object');
}
} else {
logger.debug(jsonFileName+' : '+' OK go to next');
callback(null, 'getReportName');
}
}
});
},
// Save Json on filesystem
function(callback){
logger.debug(jsonFileName+' : '+' Saving on disk');
if(_.isUndefined(json)){
logger.error('Json is undefined...');
}
fs.writeFile(jsonFileName, JSON.stringify(json), 'utf8', function (err) {
if (err) return logger.error(params);
callback(null, 'writeJson');
});
}
]);
}
Solved this using node-fetch.
Code instead of request now looks like this:
fetch(uri, { method: 'POST', body: JSON.stringify(requestBody), timeout: 600000, headers: {'content-type': 'application/json'} })
.then(function(response) {
logger.debug('Response: '+ response.status + ' ok?'+response.ok);
if (!response.ok) {
logger.debug('Received: '+response.statusText);
return respond(res,500, 'Error when getting ressource. Status='+response.status);
} else{
json = response.json();
if( _.isUndefined(json) || _.isNull(json)){
return respond(res,500, 'Error when getting ressource');
} else {
callback(null, 'getReportName');
}
}
});

api call to sinch as promise

I've tested the interface and made some changes to use with my sailsjs (version 11) on the backend. In this case I use a sails service and things seem fine but I always get back a pending status.
```
SinchService.js
var sinchAuth = require('sinch-auth');
var request = require('request');
var sinchMessaging = {};
var Promise = require('bluebird');
//sinchMessaging.sendMessage = function (phoneNumber, message) {
//exports.sendMessage = function (phoneNumber, message) {
module.exports = {
sendMessage: function (phoneNumber, message) {
var auth = sinchAuth();
if (!auth) {
throw new Error("No Authorization was provided");
}
var options = {
method: 'POST',
url: "https://messagingApi.sinch.com/v1/sms/" + phoneNumber,
headers: {
"Content-Type": "application/json",
"Authorization": auth
},
body: "{\"Message\":\"" + message + "\"}"
// body: {"Message" : message }
};
return new Promise(function (resolve, reject) {
request(options, function (error, response, body) {
sails.log("Finished with call");
if (error) {
sails.log(error);
throw error;
}
else {
sails.log("Finished with body ", body);//.MessageId
return resolve(response.body);
}
});
})
},
getStatus: function (messageId) {
var auth = sinchAuth();
if (!auth) {
throw new Error("No Authorization was provided");
}
var options = {
method: 'GET',
url: "https://messagingApi.sinch.com/v1/sms/" + messageId,
headers: {
"Content-Type": "application/json",
"Authorization": auth
}
};
return new Promise(function (resolve, reject) {
request(options, function (error, response, body) {
sails.log("Finished with call");
if (error) {
sails.log(error);
throw error;
}
else {
return resolve(response.body);
}
});
})
}
};
```
agendaService.js
var jsonObjS;
SinchService.sendMessage(phoneNumber, message).then(function (results) {
var jsonObj = JSON.parse(results);
console.log('results sendMessage ', jsonObj.messageId);
if (jsonObj.messageId!==undefined){
SinchService.getStatus(jsonObj.messageId).then(function (results_s) {
jsonObjS = JSON.parse(results_s);
console.log('results getStatusS ', jsonObjS.status);
SinchService.getStatus(jsonObjS.messageId).then(function (results_s) {
var jsonObjS = JSON.parse(results_s);
console.log('results getStatusS ', jsonObjS.status);
});
});
```
Pending will always be the first status, query again after some time to see the status of of the message.

Resources