How to get rid of UnhandledPromiseRejectionWarning in Node Mongo Express Application - node.js

Greetings!
I have a Node-Express endpoint that calls addAdminController.js (Attached Below) to create a new admin.
Everything works well from functionality point of view. However, When you check if user already exists using mongoose FindOne method, it leaves a warning on the console. This however, does not stop the function from running and I'm successfully returning "Email Already in Use" as json object in Postman.
I want to know why i'm seeing this error and what am I doing wrong with Promise Handling. Your help is much appreciated.
addAdminController.js
const adminsModel = require("../../../../models/admins");
const bcrypt = require("bcryptjs");
exports.addAdminController = async (req, res, next) => {
const { name, email, password, role, image, status } = req.body;
//check if user already exists
try {
adminsModel
.findOne({ email }, (err, admin) => {
if (admin) {
res.status(400).json("Email Already in use");
return;
}
})
.exec();
} catch (error) {
return res.status(500).json("Something Went Wrong");
}
//Encrypt Password using Bcrypt
const saltRounds = 12;
const hashPass = bcrypt.hashSync(password, saltRounds);
//Create New Model with Hashed Password
const newAdmin = new adminsModel({
name: name,
email: email,
password: hashPass,
role: role,
image: image,
status: status,
});
// Save new admin user.
try {
await newAdmin.save();
res.json(newAdmin);
return;
} catch (error) {
res.status(400).json("There was an error creating admin user");
}
};
Console Warning
node:18700) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:533:11)
at ServerResponse.header (F:07_Developrs\Github\APIv2\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (F:07_Developrs\Github\APIv2\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (F:\07_Developrs\Github\APIv2\node_modules\express\lib\response.js:267:15)
at exports.addAdminController (F:\07_Developrs\Github\APIv2\routes\api\admins\addAdmin\addAdmin.controller.js:37:19)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:18700) 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(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:18700) [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.

First of all, you shouldn't be using callback version of findOne function because code below findOne function call will execute before the callback of findOne executes.
As code below the findOne function call depends on whether user already exists or not, await the result of adminsModel.findOne(...) and check findOne function returned a user or not.
Secondly, wrap findOne function call with try-catch block to handle rejected promise.
try {
const user = await adminsModel.findOne({ email });
if (user) {
return res.status(400).json("Email Already in use");
}
// code to run if user doesn't exists
} catch (error) {
return res.status(500).json("Something Went Wrong");
}

Related

Unsure how to connect an api using nodejs

I'm trying to connect the openai api into my app but I'm not sure why it's not working. From my frontend, I have a createUserData that receives an input and then stores it to my MongoDB database. But now, I want to send that input that I received to the openai API and get a response based on what they said. I tried implementing it here but it crashed on me with this error:
UnhandledPromiseRejectionWarning: Error: Request failed with status code 401
at createError (C:\Users\simer\Downloads\Talkhappi\server\node_modules\axios\lib\core\createError.js:16:15)
at settle (C:\Users\simer\Downloads\Talkhappi\server\node_modules\axios\lib\core\settle.js:17:12)
at IncomingMessage.handleStreamEnd (C:\Users\simer\Downloads\Talkhappi\server\node_modules\axios\lib\adapters\http.js:322:11)
at IncomingMessage.emit (events.js:387:35)
at endReadableNT (internal/streams/readable.js:1317:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:17844) 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(). To terminate the node process on unhandled promise
rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:17844) [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.
For some reason I crash when I try and call this API, am I doing it wrong?
Right now I just want to log whatever the response I get from the API, once I'm able to do that then I will store it to the database as well. But I can't even log it as I get an error. Here is my code:
const { Configuration, OpenAIApi } = require("openai");
// create new user data
const createUserData = async (req, res) => {
const {id, scores, transcript} = req.body
const user_id = req.user._id
console.log(user_id)
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const response = await openai.createCompletion({
model: "text-davinci-002",
prompt: "Provide personal feedback for me and give me tips: " + transcript,
temperature: 0.7,
max_tokens: 256,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
});
console.log(response)
const newUserData = new UserData({
id: id,
scores: scores,
transcript: transcript,
user_id: user_id
})
// add doc to db
try {
await newUserData.save()
} catch (error) {
res.status(400).json({error: error.message})
}
console.log('POST:', newUserData)
return res.status(201).json({user_data: newUserData})
}

MongooseError: Query was already executed: User.countDocuments({})

(node:9540) UnhandledPromiseRejectionWarning: MongooseError: Query was already executed: User.countDocuments({})
at model.Query._wrappedThunk [as _countDocuments] (D:\Acadamic-LANGUAGE-PROJECTS\Angular-Projects\eShop-MEAN STACK\Back-End\node_modules\mongoose\lib\helpers\query\wrapThunk.js:21:19)
at D:\Acadamic-LANGUAGE-PROJECTS\Angular-Projects\eShop-MEAN STACK\Back-End\node_modules\kareem\index.js:370:33
at processTicksAndRejections (internal/process/task_queues.js:77:11)
(Use node --trace-warnings ... to show where the warning was created)
(node:9540) 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(). To terminate the node
process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:9540) [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.
this is my Code......
router.get(`/get/count`, async (req, res) =>{
const userCount = await User.countDocuments((count) => count)
if(!userCount) {
res.status(500).json({success: false})
}
res.send({
userCount: userCount
});
})
It seems that you are using Mongoose. It seems you are mixing between async-await and callbacks.
Change await User.countDocuments((count) => count) to
await User.countDocuments()
This is because countDocuments() is called using its callback (which passes its result to the callback), while on the other hand, it is also asked to pass its result to the userCount variable using the await command.
This is exactly what this error message is trying to say: hey, you're sending the same query to the database twice ! While, since since v6 of Mongoose, you can only get run query once - ie, either by adding the cbk argument, or using async-await block. Read about it here: https://mongoosejs.com/docs/migrating_to_6.html#duplicate-query-execution
Now let's move ahead to fixing the problem:
I don't completely understand what you're trying to do this in line:
const userCount = await User.countDocuments((count) => count)
I think what you're trying to do is just get the document count. If so, simply drop 'count => count'.
router.get(`/get/count`, async (req, res) =>{
const userCount = await User.countDocuments();
if(!userCount) {
res.status(500).json({success: false})
}
res.send({
userCount: userCount
});
})
If you were to add a filter to the count (which is what the countDocuments gets - a filter; see API here), then you should use the key:value pair form, ie {count: count}.
router.get(`/get/count`, async (req, res) =>{
/* let count; etc. */
const userCount = await User.countDocuments({count: count});
if(!userCount) {
res.status(500).json({success: false})
}
res.send({
userCount: userCount
});
})
Of course you should use a proper try-catch block when using await, to be able to handle the error if thrown.
(Just encountered this problem myself and made some research into it.)
module.exports.getUserCount = async(req,res)=>{
const numberOfUser = await User.countDocuments()
res.send({numberOfUser : numberOfUser});
}

UnhandledPromiseRejectionWarning: NodeJS pull request not working

I am writting following request to unfollow a user. followers are added to the database as an array.
router.put("/:id/unfollow",async (req,res) => {
if(req.body.userId !== req.params.id){
try{
const user = await User.findById(req.params.id);
const currentUser = await User.findById(req.params.id);
if (user.followers.includes(req.body.userId)){
await user.updateOne({$pull:{followers:req.body.userId}});
await currentUser.updateOne({$pull:{followers:req.params.id}});
res.status(200).json("user has been unfollowed");
}else{
res.send(403).json("you already unfollowed this user ");
}
}catch (err){
res.status(500).json(err);
console.log("err");
}
} else{
res.status(403).json("You cant unfollow yourself")
}
})
When the request is sent via postamn with the correct userId postman says "forbidden"
and the terminal shows the following error.
Whats wrong in here ?
express deprecated res.send(status): Use res.sendStatus(status) instead routes\user.js:98:21
(node:15336) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:561:11)
at ServerResponse.header (C:\Users\Banchi\Desktop\ReactTest\moodfix-api2\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (C:\Users\Banchi\Desktop\ReactTest\moodfix-api2\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\Users\Banchi\Desktop\ReactTest\moodfix-api2\node_modules\express\lib\response.js:267:15)
at C:\Users\Banchi\Desktop\ReactTest\moodfix-api2\routes\user.js:102:29
at processTicksAndRejections (internal/process/task_queues.js:95:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:15336) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a prom
ise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#c
li_unhandled_rejections_mode). (rejection id: 1)
(node:15336) [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-z
ero exit code.
inside else block of try, make following change:
try{
...
if (user.followers.includes(req.body.userId)){
...
res.status(200).json("user has been unfollowed");
} else{
// res.send(403).json("you already unfollowed this user ");
// ^^^ here is the error. It should be
res.status(403).json("you already unfollowed this user ");
}
} catch ...
Cannot set headers after they are sent to the client
This happens when you send another response behind an already sent one. And your code is doing this. First it respond with send(403) then sending json("you already unfollowed this user ") as well.

Mongoose query not running - "cursor.toArray is not a function"

MongoDB beginner, having trouble getting queries to work. Was following a tutorial of sorts and it was a demo notes app. Their syntax for saving new notes works fine.
However when it comes to printing out the list of notes, there seems to be something wrong in the syntax given to me or something im doing wrong.
const mongoose = require("mongoose");
const url =
"mongodb+srv://Saif:<password>#cluster0.8d2lb.mongodb.net/notes-app?retryWrites=true&w=majority";
mongoose.connect(url, {
useNewUrlParser: true,
});
const noteSchema = new mongoose.Schema({
content: String,
date: Date,
important: Boolean,
});
const Note = mongoose.model("Note", noteSchema);
Note.find({}).then((result) => {
result.forEach((note) => {
console.log(note);
});
mongoose.connection.close();
});
After looking up documentation, the actual syntax of find is a little different where they pass in a callback instead of using promises. But changing that block to use a callback still doesnt work
Note.find({}, (error, data) => {
if (error) {
console.log(error);
} else {
data.forEach((note) => {
console.log(note);
})
}
mongoose.connection.close()
})
Error
TypeError: cursor.toArray is not a function
at model.Query.<anonymous> (D:\Folders\Documents\CS.........
(Use `node --trace-warnings ...` to show where the warning was created)
(node:27108) 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(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:27108) [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.
.find method from model returns Query object not Cursor
For cursor you need to do .exec
Note.find({}).exec((error, data) => {
if (error) {
console.log(error);
} else {
data.forEach((note) => {
console.log(note);
})
}
mongoose.connection.close()
})

Express is res.sending both success and error - ERR_HTTP_HEADERS_SENT

I have strange problem with [ERR_HTTP_HEADERS_SENT]: : Cannot set headers after they are sent to the client. It's in try/catch, but still somehow after res.send({message: 'Company set up'}) it also sends res.send({error}) which shouldn't occur.
I also tried return res.send({message: 'Company set up'}), but I have still same error. Along with that error I also get:
(node:19234) 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: 1).
What I found that there is no problem when await knex() calls are commented out.
try {
if (req.files) { //multer
let data = req.body
const locations = JSON.parse(data.locations)
const parsedLocations = locations.map((obj, index) => {
(...)
})
await asyncForEach(parsedLocations, async (element, index) => {
const country = await knex('countries').first().where({ country: element.country })
})
console.log('company set up')
res.send({ message: 'Company set up' })
}
} catch (error) {
console.log('error')
console.log(error)
res.send({ error})
}
Here's the asyncForEach function for reference:
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
Error log from Node.js:
[ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (/Users/xx/Developer/microservice/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/Users/xx/Developer/microservice/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/xx/Developer/microservice/node_modules/express/lib/response.js:267:15)
at ServerResponse.send (/Users/xx/Developer/microservice/node_modules/express/lib/response.js:158:21)
at router.post (/Users/xx/Developer/microservice/routes/admin.js:714:11)
(node:19337) 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: 3)
This error is due to trying to send multiple response.
You can check if response has been already sent or not before returning response.
Like:
if (res.headerSent) {
res.send({ data/ error})
If already sent, then it will not send another.
Your code is not catching the error.
return res.status(405).send('User already exist');

Resources