API built in express responds with empty array - node.js

I have my application populating an array with names. I can log the array values and it is getting the values, but using postman to make a request on localhost:8888/api/messages my response says matches : [] with the empty array. Why is my array empty in the response if I do indeed populate it?
router.get('/messages', function(request, res) {
var names = [];
ctxioClient.accounts(ID).contacts().get({limit:250, sort_by: "count", sort_order: "desc"},
function ( err, response) {
if(err) throw err;
console.log("getting responses...");
var contacts = response.body;
var matches = contacts.matches;
for (var i = 0; i < matches.length; i++){
names.push(matches[i].name);
matches[i].email;
}
res.json({matches : names});
});
});

This is because the response.json() executes before the ctxioclient.get() happens. Call response.json inside .get() instead. Something like this
router.get('/messages', function(request, response) { // <--- router response
var names = [];
ctxioClient.accounts(ID).contacts().get({ limit: 250,sort_by: "count",sort_order: "desc"},function(err, resp) { // <---- using resp
if (err) throw err;
console.log("getting responses...");
var contacts = response.body;
var matches = contacts.matches;
for (var i = 0; i < matches.length; i++) {
names.push(matches[i].name);
matches[i].email;
}
response.json({ matches: names }); // <--- router response
});
});

Related

Http requests inside a for loop from angular to node.js API returns 404

I try to send several HTTP requests continuously inside a for loop to node.js rest API.
Below is how I try to send HTTP requests from my Angular Front-end.
getOthersCompletionsByTaskID is the function that send a HTTP request.
this.tasksService.getTasks().then(res=>{
let i=0;
for(i;i< this.tasksService.tasks.length; i++){
this.completionService.getOthersCompletionsByTaskID(this.tasksService.tasks[i].TaskId).then(res =>{
let cArray: any = res;
console.log("cArray ", cArray)
})
}
this.dtTrigger.next();
this.rendMyTasksTable();
})
Below is my query execution function in node API.
function queryGetExecute(qry, params, isMultiSet, callback) {
var data = [];
var dataset = [];
var resultset = 0;
request = new Request(qry, async function (err, rowCount) {
utility.sendDbResponse(err, rowCount, dataset, callback);
});
params.forEach( param => {
request.addParameter(param.name, param.type, param.val);
});
request.on('row', async function (columns) {
utility.buildRow(columns, data);
});
request.on('doneInProc', async function (rowCount, more, rows) {
if (isMultiSet == false) {
dataset = data;
} else {
dataset.push(data);
data = [];
}
});connection.execSql(request)}
Below is the function in the repository that calls the above function.
function getCompletionsByFirebaseId(req, res){
if (req.params.firebaseId && req.params.taskId) {
var parameters = [];
parameters.push({ name: 'firebaseId', type: TYPES.NVarChar, val: req.params.firebaseId});
parameters.push({ name: 'taskId', type: TYPES.NVarChar, val: req.params.taskId});
var query = "select users.[name], completedById, [status], completionImage,completionId,exchangeTaskId from Tasks join completions on Tasks.TaskId=completions.taskId join users on users.firebaseId = completions.completedById where taskownerId=#firebaseId and Tasks.TaskId = #taskId"
dbContext.getQuery(query, parameters, false, function (error, data) {
if (data) {
req.data = data[0];
let finaldata = res.json(response(data, error));
return finaldata
}else{
return res.sendStatus(404);
}
});
}else
{
return res.sendStatus(404)
}
}
When I do requests like this, API returns 404. but the first request is becoming successful. rest requests returning 404. What am I doing wrong here?

Pass variable from app.get to pug view

I have the below code that make a call to my DB and pulls down info
// GET the number of apples left in stock
app.get('/apples', function (req, res) {
sql.connect(config, function() {
var request = new sql.Request();
request.query("select quantity from table WHERE type = 'apple'", function(err, recordset) {
var arrayLength = recordset.length;
for (var i = 0; i < arrayLength; i++) {
console.log(recordset[i]["quantity"]);
res.render('index', {results: recordset});
};
});
})
})
this works perfectly .. when i browse to that it sends me to the index page and then i can see the values from the DB spit out in my console log
In my index.pug I then have this
h3(align='middle') #{results}
On the index page I just see this [object Object]
First off all you shouldn't call res.render multiple times in the for loop.
app.get('/apples', function (req, res) {
sql.connect(config, function () {
var request = new sql.Request();
request.query("select quantity from table WHERE type = 'apple'", function (err, recordset) {
var arrayLength = recordset.length;
for (var i = 0; i < arrayLength; i++) {
console.log(recordset[i]["quantity"]);
};
res.render('index', { results: recordset });
});
});
});
Then you should use each in your pug file to iterate resultset.
More doc for iteration : https://pugjs.org/language/iteration.html
each val in results
h3(align='middle')=val.quantity

How could I return an array from my module to my API using promise? Async Functions and Promise - Node.js

I need to return a json object to my api. To do this I have a module that does some requests and should return the results.
My problem is grasping the promise concept and implementing it.
server.js
app.get('/users', function(req, res){
request.getUsers()
.then(function(users){
console.log(users);
res.contentType('application/json');
res.send(JSON.stringify(users));
})
.catch(function(){
console.log(users);
});
});
module.js
exports.getUsers = function(){
var params = {search_string:""};
var users = [];
return new Promise(function(resolve, reject){
var result = connection.Users.get(params, function(error,response)
{
var user = [];
for(let i = 0; i < response.data.length; i++)
{
user = response.data;
}
users.push({user});
});
if(result != null)
{
console.log(result);
resolve(result);
}
else
{
reject(new Error('Try Again'));
}
});
}
When I run the server I get the typeError: expecting a function but got [object object]
I did not really get what is wrong.
How could I return an array from my module to my API using promises?
EDIT:
app.get('/users', function(req, res){
request.getUsers()
.then(function(users){
console.log(users);
res.contentType('application/json');
res.send(JSON.stringify(users));
})
.catch(function(){
console.log("not resolved");
});
});
My problem now is actually that I am getting the .catch even before any request is made the at /users endpoint and I dont know why.
In module.js you used new Promise() constructor but the input parameter should be a function and not an object, so to fix that use:
return new Promise(function(resolve, reject) {
var result = connection.Users.get(params, function(error,response)
...
});
Notice its not new Promise({function(...) but new Promise(function(...)) ...
Read more here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Edit:
I have modified your code to work to fix the second problem:
exports.getUsers = function(){
var params = {search_string:""};
var users = [];
return new Promise(function(resolve, reject){
var result = connection.Users.get(params, function(error,response) {
if(error || !response)
{
// report error
reject(new Error('Try Again'));
}
else
{
//process response
var user = [];
for(let i = 0; i < response.data.length; i++)
{
user = response.data;
}
users.push({user});
// report success
resolve(users);
}
});
}
You need to call resolve or reject inside connection.Users.get(params, function(error,response) {
Modify your module.js code as below. You passed an object instead of a function.
register.getUsers = function () {
var params = { search_string: "" };
var users = [];
return new Promise(function (resolve, reject) {
var result = connection.Users.get(params, function (error, response) {
var user = [];
for (let i = 0; i < response.data.length; i++) {
user = response.data;
}
users.push({ user });
});
if (result != null) {
console.log(result);
resolve(result);
}
else {
reject(new Error('Try Again'));
}
});
};
you declared user variable as an array and inside the for loop isn't useful because the user variable is always equals to response.data
if response.data is array of JSON object you can push it to users array inside loop
for (let i = 0; i < response.data.length; i++) {
users.push(response.data[i]);
}
I guess you want to return the array of objects
also I recommend you to use bluebird module to return promises
and also you can use Promise.mapSeries instead of for loop like:
return Promise.mapSeries(response.data, item => {
users.push(item)
})

Node js Printing info from JSON file using a function from another file V2.0

This is a continuation from another question I asked earlier Node.js Printing info from JSON file using a function from another JS file
In my previous question I had problems in calling a function from my data-service.js file that printed all the items in my JSON array, and had it resolved, but now I'm struggling in doing something similar in printing only the employees from my JSON array that I specify through the url. For example http://localhost:8080/employeesstatus=5 would print only the employee with a status of 5 however nothing is getting printed
SERVER.JS
var HTTP_PORT = process.env.PORT || 8080;
var express = require('express');
var data = require('./data-service');
var fs = require('fs');
var app = express();
var object = require('./data-service');
console.log("Express http server listening on 8080");
//app.get('/employees', function(req,res){
// return object.getAllEmployees()
// .then((response) => res.send(response))
//}); //QUESION FROM PREVIOUS POST WHICH WAS RESOLVED
app.get('/employees:?status=:value', function(req,res){
return object.getEmployeesByStatus(req.params.value)
.then((response) => res.send(response));
});
DATA SERVICE.JS
var employees = [];
var departments = [];
var error = 0;
var fs = require("fs");
function initialize(){
employees = fs.readFileSync("./data/employees.json", 'utf8', function(err, data){
if(err){
error = 1;
}
employees = JSON.parse(data);
});
departments = fs.readFileSync("./data/department.json", 'utf8',
function(err, data){
if(err){
error = 1;
}
departments = JSON.parse(data);
});
}
function check() {
return new Promise(function(resolve,reject){
if (error === 0){
resolve("Success");
}
else if(error === 1){
reject("unable to read file");
}
})
};
var getAllEmployees = function(){
return check().then(function(x){
console.log(x);
console.log(employees);
return employees;
}).catch(function(x){
console.log("No results returned");
});
}
var getEmployeesByStatus = function (status){
return check().then(function(x){
var employees2 = JSON.parse(employees);
for (var i = 0; i<employees2.length; i++){
if (employees2[i].status == status){
return console.log(employees2[i]);
}
}
}).catch(function(){
console.log("no results returned");
})
}
module.exports.getAllEmployees = getAllEmployees;
module.exports.getEmployeesByStatus = getEmployeesByStatus;
The 2 functions in question
app.get('/employees:?status=:value', function(req,res){
return object.getEmployeesByStatus(req.params.value)
.then((response) => res.send(response));
});
var getEmployeesByStatus = function (status){
return check().then(function(x){
var employees2 = JSON.parse(employees);
for (var i = 0; i<employees2.length; i++){
if (employees2[i].status == status){
return employees2[i];
}
}
}).catch(function(){
console.log("no results returned");
})
}
1) You should replace /employees route with the following
app.get('/employees/status=:value', function(req,res){
return object.getEmployeesByStatus(req.params.value)
.then((response) => res.send(response));
});
You are able to access using http://localhost:8080/employees/status=5
2) Return employees2[i] instead of console.log(employees2[i]).

Node.js async - build object from loop, then do something with object

I'm trying to run a function and once that function is complete, then run another function. The first function reads a CSV file, makes a GET request, and builds an object. The second function uses that newly created object to create a new CSV file.
The problem I'm having is that the new CSV file is being created prior to the GET requests finishing.
I'm using async.parallel to set the flow, but not able to get the logic right.
I'd love to know what I'm doing wrong and better understand how node thinks about these tasks.
// Require
var request = require('request');
var fs = require('fs');
var json2csv = require('json2csv');
var csv = require('csv');
var async = require('async');
// Params
var emailHunter_apiKey = '0000';
var emails = [];
var fields = ['email'];
var i = 0;
// Start
async.parallel([
function(callback){
setTimeout(function(){
var file = fs.readFileSync('file.csv');
csv.parse(file, {delimiter: ','}, function (err, data) {
for (var key in data) {
if (i < 5) {
if (data.hasOwnProperty(key)) {
var h = data[key];
if (h[5] != '') {
var url = h[5];
url = url.replace('//', '');
url = url.replace('www.', '');
request('https://api.emailhunter.co/v1/search?domain=' + url + '&api_key=' + emailHunter_apiKey + '', function (error, response, body) {
if (!error && response.statusCode == 200) {
var json = JSON.parse(body);
for (var subObj in json) {
if (json.hasOwnProperty(subObj) && subObj == 'emails') {
var emailObj = json[subObj];
for (var key in emailObj) {
var email = {
'email': emailObj[key]['value']
};
emails.push(email);
}
}
}
}
});
}
}
}
i++;
}
});
callback(null, emails);
}, 200);
console.log(emails);
}
],
function(err, results){
json2csv({data: results, fields: fields}, function (err, csv) {
if (err) console.log(err);
fs.writeFile('export.csv', csv, function (err) {
if (err) throw err;
console.log('file saved');
});
});
console.log(results);
});
As laggingreflex mentioned, you're using async incorrectly.
First you should build a an array of functions that you want to execute in parallel. And then use async to execute them.
Furthermore, your callback was getting executed immediately because csv.parse() is an async function. Therefore node fires it immediately and then executes callback(). You need to move the callback inside of parse().
Try this...
// Params
var emailHunter_apiKey = '0000';
var emails = [];
var fields = ['email'];
var i = 0;
var functionsToRunAsync = [];
var file = fs.readFileSync('file.csv');
csv.parse(file, {delimiter: ','}, function (err, data) {
for (var key in data) {
if (i < 5) {
if (data.hasOwnProperty(key)) {
var h = data[key];
if (h[5] != '') {
var url = h[5];
url = url.replace('//', '');
url = url.replace('www.', '');
// add a new function to an array, to be executed later
functionsToRunAsync.push(function(callback) {
request('https://api.emailhunter.co/v1/search?domain=' + url + '&api_key=' + emailHunter_apiKey + '', function (error, response, body) {
if (!error && response.statusCode == 200) {
var json = JSON.parse(body);
for (var subObj in json) {
if (json.hasOwnProperty(subObj) && subObj == 'emails') {
var emailObj = json[subObj];
for (var key in emailObj) {
var email = {
'email': emailObj[key]['value']
};
emails.push(email);
// callback to tell async this function is complete
callback()
}
}
}
} else {
// callback to tell async this function is complete
callback
}
});
});
}
}
}
i++;
}
// now that we have all of the functions in an array, we run them in parallel
async.parallel(
functionsToRunAsync,
function(err, results) { // all async functions complete
json2csv({data: results, fields: fields}, function (err, csv) {
if (err) console.log(err);
fs.writeFile('export.csv', csv, function (err) {
if (err) throw err;
console.log('file saved');
});
});
console.log(results);
});
});

Resources