let { errors } = otherValdations(data);
withDB(async (db) => {
return Promise.all([
..code...
]).then(() => {
return {
errors,
isValid: isEmpty(errors),
}
})
}, res).then((result) => {
console.log(result);
})
How can I get 'result' variable to be the value of the object returned in promise.all? This is the code for withDB function:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('app');
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error});
}
};
You need to modify withDB() so that it returns the value you want:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('app');
let result = await operations(db);
client.close();
return result;
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error});
throw error;
}
}
In your catch() handler, you also need to do something so that your calling code can distinguish the error path where you've already sent an error response from the case where you're resolved with the value. I don't know exactly how you want that to work, but I put in a throw error so that it will reject the returned promise and the caller can see that.
I notice from your error handling that you are assuming all possible errors are causing by an error connecting to the DB. That is not the case here. If operations(db) rejects, that will also hit your catch.
Promise.all returns an array with the results. So you either have to loop over the results or access them directly by supplying an index.
Related
I want to delete a file and wait for the deletion to succeed before moving forward. I have used unlink function inside a promise to get the result, but when unlink done successfully then I am getting the result from the promise if there is any kink of error while deleting the file the promise does not return any error.
Service:
public removeUserImage(
user: User,
): Promise<NodeJS.ErrnoException | boolean> {
const pathToRemoveImage = 'src/public/uploads'+ '/' + user.image_url;
return new Promise((resolve, reject) => {
unlink(pathToRemoveImage, (error) => {
if (error) reject(error);
resolve(true);
});
});
}
Controller:
const isFileRemoved = await this._userService.removeUserImage(user);
//This block not excuting
if (!isFileRemoved) {
throw new InternalServerErrorException(
'Error occurred while trying to remove file.',
);
}
Your promise rejects if there's an error. When using await, you need to wrap the code in try..catch in order to handle any failures
try {
await this._userService.removeUserImage(user);
} catch (err) {
console.error(err);
throw new InternalServerErrorException(
'Error occurred while trying to remove file.'
);
}
FYI, you can (and should) use the Promises API versions of the fs functions
import { unlink } from "node:fs/promises";
public removeUserImage({ image_url }: User): Promise<void> {
const pathToRemoveImage = `src/public/uploads/${image_url}`;
return unlink(pathToRemoveImage);
}
If you wanted your method to always resolve with a Boolean, you'd want something like
return unlink(pathToRemoveImage)
.then(() => true) // resolve with "true" for success
.catch((err) => {
console.error("removeUserImage", image_url, err);
return false; // resolve with "false" for failure
});
The error will always go to catch block,
try {
await this._userService.removeUserImage(user);
} catch (err) {
console.error(err);
throw new InternalServerErrorException(
'Error occurred while trying to remove file.'
);
}
Suggestion: You don't need to convert unlink(callback) to promise fs has promise function also, check this
const fs = require('fs');
const fsPromises = fs.promises;
public removeUserImage(
user: User,
): Promise<void> {
const pathToRemoveImage = 'src/public/uploads'+ '/' + user.image_url;
return fsPromises.unlink(pathToRemoveImage);
}
The problem is that i am getting UNhandledPromiseRejection error eveen though i think i have handled all the cases. The code flows from profileRoutes to Controller to Utils where the error comes first.
Inside the profileRoutes.js
router.get('/:username', async (r, s) => {
try{
let profileData = await getProfileData(r.params.username);
s.json({ success: true, payload: profileData });
}catch(err){
console.log('ending request processing by responding a error');
s.status(500).json({ success: false, message: 'err[0].message' });
}
});
Inside the controllers/index.js
const fetchQueue = [getUserRepos];
async function getProfileData(username) {
let profileData = {};
try{
let results = await Promise.all(fetchQueue.map(item => item(username)));
for (let i = 0; i < results.length; i++) {
profileData[getKeys[i]] = results[i];
}
return profileData;
}catch(err){
console.log('error log in controller/index getProfileData function');
throw err;
}
}
const getUserRepos = async (username) => {
try {
// const res = await utils.gqlSender(username, 'userRepos', { createdAt });
const res = await utils.gqlSender(username, 'userReposData');
return res.user.repositories;
} catch (err) {
console.log('error log in controller/index getUserRepos function');
throw err;
}
};
Inside the utils/index.js
const gqlSender = async (username, type, opt = {}) => {
axios.post('', {
query: gqlQuery(username, type, opt) // generates a needed graphQL query
}).then(res => {
if(res.data.errors) { // this is where the error is recieved and so i reject promise.
console.log('bef###re');
return Promise.reject (res.data.errors);
}
console.log('###',res.data);
return res.data;
}).catch(err => {
console.log('error in making axios request inside utils/index gqlSender function');
throw err;
// return Promise.reject(err);
});
The stack trace on making get request to /:username is-
error log in controller/index getUserRepos function
error log in controller/index getProfileData function
ending request processing by responding a error
bef###re
error in making axios request inside utils/index gqlSender function
(node:11260) UnhandledPromiseRejectionWarning: [object Array]
(node:11260) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:11260) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I dont think i am missing any Promise Rejection.
Any help is appreciated. Thanks.
i have referred these answers previously -
What's the difference between returning value or Promise.resolve from then()
Do I need to return after early resolve/reject?
Your gqlSender function is not returning the promise that will get rejected, so it is not handled anywhere. You should write either
const gqlSender = (username, type, opt = {}) => {
return axios.post('', {
// ^^^^^^
query: gqlQuery(username, type, opt) // generates a needed graphQL query
}).then(res => {
if (res.data.errors) {
console.log('error in making axios request inside utils/index gqlSender function');
throw res.data.errors;
} else {
console.log('###',res.data);
return res.data;
}
});
};
or
const gqlSender = async (username, type, opt = {}) => {
// ^^^^^
const res = await axios.post('', {
query: gqlQuery(username, type, opt) // generates a needed graphQL query
});
if (res.data.errors) {
console.log('error in making axios request inside utils/index gqlSender function');
throw res.data.errors;
} else {
console.log('###',res.data);
return res.data;
}
}
I've been trying to create a helper function to return a document's data from the Firebase database using Nodejs:
module.exports = async (collectionName, documentId, res) => {
const collection = db.doc(`/${collectionName}/${documentId}`);
try {
const targetedDocument = await collection.get();
if (!targetedDocument.exists) {
return res.status(404).json({
error: true,
message: `the document ${documentId} is not exists.`,
});
}
return targetedDocument.data();
} catch (error) {
return res.status(500).json({ error: true, message: error });
}
};
But when I tried to use it, it always returns back a promise:
const documentFinder = require('./helper-function-path');
router.post('post',(req,res)=>{
const requiredDocument = documentFinder("post", "Izkn12IMnayzokLqe",res);
console.log(requiredDocument); //returned a promise rather than an object document
})
What am I doing wrong here? Some pointer would be very much appreciated. Thank you.
async functions, by definition, always return a promise. You can't make an asynchronous function to be synchronous simply by wrapping it. The caller will always still have the promise to deal with. You can deal with the returned promise in your express route by making its callback also async, and awaiting the result of the function call:
router.post('post', async (req,res)=>{
const requiredDocument = await documentFinder("post", "Izkn12IMnayzokLqe",res);
console.log(requiredDocument);
})
Please try out:
module.exports = async (collectionName, documentId, res) => {
const collection = db.doc(`/${collectionName}/${documentId}`);
try {
const targetedDocument = await collection.get();
if (!targetedDocument.exists) {
return res.status(404).json({
error: true,
message: `the document ${documentId} is not exists.`,
});
} else {
return targetedDocument.data();
}
} catch (error) {
return res.status(500).json({ error: true, message: error });
}
};
So when running a query using Objection.js, the query will return data based on success or failure of said query and this data is passed to the then() block as a 0 or 1. Meaning to error handle, I'm having to check falsey values rather than send a response in the catch block. Am I doing something wrong?
const editIndustry = async (req, res, next) => {
const industry = await Industry.query().findById(req.params.industryId);
if (!industry) {
return res.status(404).json({
error: 'NotFoundError',
message: `industry not found`,
});
}
await industry
.$query()
.patch({ ...req.body })
.then(result => console.log(result, 'then() block'))
// never runs
.catch(err => {
console.log(err);
next(err);
});
};
App is listening on port 3000.
1 then() block ran
Your code is working as expected. The reason it's not going into the catch block is because there isn't an error. patch does not return the row. It returns the number of rows changed (see docs).
The function I think you're really looking for is patchAndFetchById (see docs). If you're concerned about generating a 404 error, you can append throwIfNotFound. Obviously, this will throw if it's not found in the database, which will let you catch. You can catch an instance of this error so you can send a proper 404 response. Otherwise, you want to return a 500. You'd need to require NotFoundError from objection.
const { NotFoundError } = require('objection');
const Industry = require('<myIndustryModelLocation>');
const editIndustry = (req, res) => {
try {
return Industry
.query()
.patchAndFetchById(req.params.industryId, { ...req.body })
.throwIfNotFound();
} catch (err) {
if(err instanceof NotFoundError) {
return res.status(404).json({
error: 'NotFoundError',
message: `industry not found`,
});
}
return res.status(500);
}
};
I have an async function which inserts some data into a database (using mariadb). This insert may fail due to a duplicate unique key, so it'll throw an error (and it actually does), but when I try to throw it again to catch it through the Promise, it doesn't work; it always seems to end in a successful case, even if it has thrown the error.
I tried changing the then/catch order, and I used reject(err); instead of throw err; but none of that works.
Here's the POST declaration:
router.post('/', function (req, res) {
var user = req.body || {};
createUser(user).then(() => {
res.status(201);
res.send('Created!'); // This is ALWAYS sent, with the error thrown or not
}).catch(err => {
console.log('thrown'); // This is never printed
res.status(500);
res.send('Failed');
});
});
And this is the create user function:
async function createUser(user) {
let conn;
try {
conn = await db.getConnection();
const res = await conn.query('INSERT INTO users VALUES (NULL, ?, ?)', [user.name, user.password]); // Shorter example
return res;
} catch (err) {
console.log('catched'); // This is printed
throw err; // This is run but nothing thrown
} finally {
if (conn) {
return conn.end(); // This is run after catching
}
}
}
The idea would be to get that exception caught by the Promise so I can send an error message instead of a success.
The problem is with your return statement inside your finally. In an async function after throwing an exception if you catch it throw finally and return something, instead of throwing it resolves the promise into your returned value. From what I see you do not need the ended connection's object as the return value which means all you have to do is to change your function to this:
async function createUser(user) {
let conn;
try {
conn = await db.getConnection();
const res = await conn.query('INSERT INTO users VALUES (NULL, ?, ?)', [user.name, user.password]); // Shorter example
return res;
} catch (err) {
console.log('catched'); // This is printed
throw err; // This is run but nothing thrown
} finally {
if (conn) {
conn.end(); // This is run after catching
}
}
}