So, im my nodeJS project I have this part of my code, that is not waiting for the await call
Controller.js
exports.getList = async function(request, response) {
try {
const result = await useCase.getList()
if (result == undefined) {
utils.unavailable(response)
}
else if (result == null || result.length == 0) {
utils.respond(response, 404, errCodes.NOT_FOUND)
}
else utils.respond(response, 200, result)
}
catch(e) {
utils.unavailable(response)
}}
This is the function on the controller, it calls the response from the useCase
UseCase.js
exports.getList = async function() {
return await new Promise(function(resolve) {
resolve(repository.getList())
})
Which also calls the repository
Repository.js
exports.getList = async function() {
MongoClient.connect(Constants.DB_URL, function(err, db) {
if (err) {
console.log(err)
return undefined
}
const dbo = db.db(Constants.DB_NAME)
dbo.collection(Constants.DB_FEATURE1_COLLECTION).find({}).toArray(function(err, result) {
if (err) {
console.log(err)
return undefined
}
db.close()
return result
})
});
So, what happens is that on the controller, the result is always undefined, since result hasn't been initialized, when it should have actually waited for the response of the Promise on the UseCase. So what am I doing wrong?
getList function does not have return statement, and since it is async it returns a Promise that always resolves with undefined. I am not very familiar with MongoClient, but documentation says it returns a promise if no callback is specified. So you can change your code:
exports.getList = async function () {
try {
const db = await MongoClient.connect(Constants.DB_URL);
const dbo = db.db(Constants.DB_NAME);
const result = await dbo.collection(Constants.DB_FEATURE1_COLLECTION).find({}).toArray();
db.close();
return result
} catch (err) {
console.log(err);
return undefined
}
};
and UseCase.js:
exports.getList = function() {
return repository.getList(); // it returns a Promise there is no need to wrap it in async
};
Related
I have a class on my node server, each function of it returns something from another api, the first function that I will show does not use a parameter, it returns the items correctly, the second that uses the Make parameter, does not return anything, and does not point out error
function getInventory:
(this function works normally)
async getInventory() {
try {
let res = await axios.get(URL);
let data = res.data;
return data;
} catch (err) {
return err;
}
}
function getMakesNew(make): (this function works without errors but does not return anything)
async getMakesNew(make) {
try {
let res = await axios.get(URL);
let data = res.data;
let count = 0;
while (data != make) {
if (data[count].ID === make) {
return data[count].Name;
} else {
count++;
}
}
} catch (err) {
return err;
}
}
Calling the two functions on the routes:
// GetInventory
routes.get('/getInventory', async (req, res) => {
return res.json(await Vehicle.getInventory());
});
// getMakesNew
routes.get('/getMakesNew/:make', async (req, res) => {
let { make } = req.params;
return res.json(await Vehicle.getMakesNew(make));
});
function getMakesNew returns:
{}
return keyword is missing from your second function
I'm unable to use async/await inside a 'new Promise' block which throws await is only valid in async function error. I don't know if it's even possible but I need to use it or a way to achieve what I want. Here's what I'm trying to do:
A user types in a query and it goes through a recursive function called doesExist. I have to use a recursive function because the API doesn't always provide data for a query. The recursive function will try 3 times, that is, it will send 3 api requests for the data before returning an error saying 'data couldn't be fetched'. In the function, I return a new promise as I have to make api requests from there.
To fetch data, I used request before but I want to use axios now with async/await. So how can I use axios with async/await inside a new Promise block?
This is the code with request:
router.get('/example', async (req, res) => {
try{
const query = 'Superman';
const data = await doesExist(query);
if(!data) {
console.log('No data');
}
res.render('../views/example', { data, query });
}catch(err) {
console.log(err);
}
});
const doesExist = (query, retries = 0) => {
const url = `http://api.example.com/json?fields=${query}`;
const maxRetries = 3;
return new Promise(( resolve, reject ) => {
const retry = () => {
if (retries < maxRetries) {
resolve(doesExist(query, retries + 1));
} else {
reject(`Could not get the data after ${retries} retries.`);
}
};
request(url, function (error, response, body) {
if (!error && response.statusCode === 200) {
const data = JSON.parse(body);
resolve(data);
} else {
retry();
}
});
});
};
And this is what I tried with async/await which throws the error:
const doesExist = async (query, retries = 0) => {
const url = `http://api.example.com/json?fields=${query}`;
const maxRetries = 3;
return new Promise(( resolve, reject ) => {
const retry = () => {
if (retries < maxRetries) {
resolve(doesExist(query, retries + 1));
} else {
reject(`Could not get the data after ${retries} retries.`);
}
};
const data = await axios.get(url);
if(data.statusCode === 200) {
resolve(data);
}else{
retry();
}
});
};
If it's not possible to use async/await inside promise block then please show me how I can achieve it. Thanks
Never pass an async function as the executor to new Promise! If you want to use async/await and axios which already does return a promise, you don't need - and shouldn't use - the Promise constructor to promisify a callback API. Just write
async function doesExist(query, retries = 0) {
const url = `http://api.example.com/json?fields=${query}`;
const maxRetries = 3;
const data = await axios.get(url);
if (data.statusCode === 200) {
return data;
} else if (retries < maxRetries) {
return doesExist(query, retries + 1);
} else {
throw new Error(`Could not get the data after ${retries} retries.`);
}
}
The function the promise calls needs to be an "async" function like so.
new Promise (async (Resolve) => {
await new Promise (async (_Resolve) => {
console.log ("A");
_Resolve ();
});
console.log ("B");
Resolve ();
});
I'm having issues with getting the result of a callback function. Below is the async function that I'm calling
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err);
} finally {
if (conn) return conn.end();
}
}
module.exports = {
'utils': utils
}
the console log above returns the expected result.
and below is the function that calls the above
const db = require('../private/db');
db.utils.sendQuery(queryString).then(function(result){
console.log(result);
}).catch(err=>{
throw res.render('error', {'error': err.stack});
})
the console log above returns undefined and I have no idea why.
The real problem here is this part if (conn) return conn.end();.
Whenever you are using finally, it will override any previous return, break, continue or throw that happens either in the stated try or catch blocks.
To fix your issue you should do like so:
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err);
} finally {
if (conn) conn.end();
}
}
module.exports = {
'utils': utils
}
Hope it works
In my opinion, just return results instead of resolve(results). Your function is already async and no promise object is created here.
And just throw err instead of reject(err);
And since you return in your try, you don't need your finally statement.
You need to simply return the result instead of calling resolve
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err)
} finally {
if (conn) return conn.end();
}
}
module.exports = {
'utils': utils
}
you could simply return or i suppose this is what you were trying to do
sendQuery: (query) => {
let promise = new Promise(async (resolve, reject) => {
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
resolve(results);
} catch (err) {
reject(err);
} finally {
if (conn) {
conn.end();
}
}
})
return promise;
}
I'm trying to use pg-pool to query a Postgresql database. And then export this data to a Node.js express rest API.
Here's my exports function.
exports.getDashboard = function(req, response, next) {
let returnData = fetchData();
return response.status(200).json(returnData);
};
Which calls fetchData();
fetchData = async function() {
let returnData = [];
returnData.languages = await getLatestLanguages();
return returnData;
};
Which calls getLatestLanguages()
getLatestLanguages = function() {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
throw error;
}
return results.rows;
}
);
}
If i place a console.log(results.rows) before getLatestLanguages() returns results.rows, then I get the data logged to the console.
However the object isn't being returned to fetchData. I tested this by logging the returnData to console before it is returned to exports.getDashboard();
I believe my problem is something to do with the async nature of pg-pool so I tried making my function async with an await but that didn't help.
What am I doing wrong?
you need getLatestLanguages to return a Promise, so you can await it from the caller
getLatestLanguages = function() {
return new Promise((resolve, reject) => {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
reject(error);
}
resolve(results.rows);
}
);
})
}
you also need to await fetchData(), therefore getDashboard should be async
exports.getDashboard = async function(req, response, next) {
let returnData = await fetchData();
return response.status(200).json(returnData);
};
getLatestLanguages() should return a promise. For example
getLatestLanguages = function() {
return new Promise((resolve, reject) => {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
reject(error);
}
resolve(results.rows);
}
);
});
};
fetchData() is async and therefore should be awaited
exports.getDashboard = async function(req, response, next) {
let returnData = await fetchData();
return response.status(200).json({ languages: returnData.languages });
};
Also make sure that you return returnData.languages in the correct format as above instead of ...json(returnData);
I am using a node npm module in a next js app to get data from an api.
static async getInitialProps() {
const zxapi = new Zxapi(connectId, secretKey);
const res2 = await zxapi.programs({ region: "DE" }, function(err, result) {
if (err != null) {
return err
}
console.log(result, "before return");
return result
console.log(result, "after return");
});
return { res2 };
}
I need to return the values of res2. The "before return" console.log logs the data to the terminal and terminates there. What am I doing wrong? Thanks
Can you check if zxapi.programs returns a Promise? If it doesn't, you might have to create a function that makes it return a Promise.
For example, you can use something like
function zxpromise() {
return new Promise((resolve, reject) => zxapi.programs({ region: "DE" }, function(err, result) {
if (err != null) {
reject(err);
}
console.log(result, "before return");
resolve(result);
console.log(result, "after return");
}));
}
and then, you can call zxpromise as
const res2 = await zxpromise()