deleting an image in a mean stack application - node.js

i want to delete the images that i uploaded in the server but every time i get an error
and only the element in the mongodb document are being deleted
this is my code
exports.removeImage = async (req, res) => {
try {
fs.unlinkSync('./images/'+req.filename);
const deleteImage = await Image.findByIdAndDelete(req.params.id)
res.json({ message: 'deleted Image successfully' });
}
catch (err) {
console.log(err);
res.status(500).json({ message: 'Internal server error' });
}
}
i think the problem is in req.filename its returning an undifiened value i tried req.body.filename but still no result

i resolved the problem by adding
const image = await Image.findById(req.params.id)
then i used image.filename in fs.unlinkSync
this is the result :
exports.removeImage = async (req, res) => {
try {
const image = await Image.findById(req.params.id)
fs.unlinkSync('./images/'+image.filename);
const deleteImage = await Image.findByIdAndDelete(req.params.id)
res.json({ message: 'deleted Inspecstib successfully' });
}
catch (err) {
console.log(err);
res.status(500).json({ message: 'Internal server error' });
}
}

Related

Cannot set headers after they are sent to the client in Express js

I'm getting this error while running this code. The API is running fine, after that it is throwing this error.
app.post('/api', async (req, res) => {
try {
channelTwo.consume(queue, async (data) => {
if (data) {
const _data = JSON.parse(data.content);
const SavedData = new User(_data);
await SavedData.save();
channelTwo.ack(data);
if (SavedData) {
res.status(200).json({ message: 'Date Saved to db', SavedData });
}
res.status(400).json({ message: 'Cant save data' });
}
res.status(400).json({ message: 'Cant find data' });
});
} catch (error) {
res.status(400).json({ message: error });
}
})
;
You have to return after calling res.status(<>).json() otherwise it will be called multiple times.
This will try to set a response header code although already json body has already been sent causing your error

Node Express.js Middleware, end Response

validateRegister: async (req, res, next) => {
UserModel.findOne({email:req.body.email}, (err, example) => {
console.log(example);
if(err) console.log(err);
if(example) {
res.status(400).json({message: "Email already registered!"});
res.end() //next('route')
}
});
console.log("test");
const user = new UserModel(req.body);
await user.save((err) => {
if (err) return res.status(500).json({ message: "Database issue!" });
});
next();
},
Ok, I tried to insert user data if it is not already in the database using mongoose. If the User regarding the email is already in the database the response should be ended and the user not inserted. I tried to end the response with res.end() and next('route'), but nothing seems to work, the console.log("test") still runs.
Error:
events.js:353
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:561:11)
Thanks for your help
Code below callback function gets executed before callback gets completed and multiple res.send happened.
you can try this
validateRegister: async (req, res, next) => {
UserModel.findOne({ email: req.body.email }, (err, example) => {
console.log(example);
if (err) {
console.log(err);
return res.status(500).json({ message: "Something went wrong" });
}
if (example) {
return res.status(400).json({ message: "Email already registered!" });
}
console.log("test");
const user = new UserModel(req.body);
await user.save((err) => {
if (err) return res.status(500).json({ message: "Database issue!" });
});
});
next();
}
Or
validateRegister: async (req, res, next) => {
try {
let example = await UserModel.findOne({ email: req.body.email });
console.log(example);
if (example)
return res.status(400).json({ message: "Email already registered!" });
console.log("test");
const user = new UserModel(req.body);
await user.save((err) => {
if (err) return res.status(500).json({ message: "Database issue!" });
});
next();
} catch (err) {
console.log(err);
return res.status(500).json({ message: "Something went wrong" });
}
}
you can add return before returning response in the case of user email already found.
What seems to happen is that your program is calling res two times

How to switch back to async/await?

I am new to async/await so I have an exercise like below code, I have converted this code to async/await many times and still no success. Please help me. Thanks very much!
My code is as follows:
exports.register = (req, res) => {
const user = req.body;
try {
// Validate the registration form
validateRegisterForm(user)
.then((response) => {
// If response is true, hash the password
if (response) {
Md5Password(user.password)
.then(async (hash) => {
const { name, email } = user;
const newUser = new User({
name,
password: hash,
});
// Save the user
const savedUser = await newUser.save();
res.status(200).json(savedUser);
})
.catch((error) => {
res.status(500).json({
message: error.message,
err: "500: Internal Server Error",
});
});
}
// But if response is false, show the error message
else {
res.status(401).json({
message: errorMessage(),
error: "401: Unauthorized",
});
}
})
.catch((error) => {
res.status(500).json({
message: error.message,
err: "500: Internal Server Error",
});
});
} catch (error) {
res.status(500).json({
error: error.message,
message: "registration failed",
e: "500: Internal Server Error",
});
}
};
Please help me, thanks a lot!
Not sure exactly what you're trying to achieve, but here's a version of your code with async/await:
exports.register = async (req, res) => {
const user = req.body;
try {
// Validate the registration form
const response = await validateRegisterForm(user);
// If response is true, hash the password
if (response) {
const hash = await Md5Password(user.password);
const { name, email } = user;
const newUser = new User({
name,
password: hash,
});
// Save the user
const savedUser = await newUser.save();
res.status(200).json(savedUser);
} else {
res.status(401).json({
message: errorMessage(),
error: "401: Unauthorized"
});
}
} catch (e) {
res.status(500).json({
message: e.message,
err: "500: Internal Server Error"
});
}
}

Mongoose , response is not correct after remove

How can I get a full data except deleted, after delete?
Project.findOneAndRemove({_id: projectID, name: projectName},
function(err, project){
if (err) {
return res.json({message: 'Error on the server!', status: 500 });
}
// Here I need a full data except deleted one
console.log(project)
return res.json({project, status:200});
}
)
or Do I find again inside success callback to get full data?
Project.find({}, function(err, projects){
if (err) return res.json({message: 'Error on the server!', status: 500 });
return res.json(projects);
});
This might help you.
router.post('/deleteAndReturn', async (req, res) => {
try {
await Project.findOneAndRemove({ _id: projectId })
const projects = await Project.find({})
return res.status(200).json(projects)
} catch (err) {
res.status(500).send("Server Error")
}
})

Keep getting "Can't set headers after they are sent" using Node/Express

I keep getting "Can't set headers after they are sent" building a Node/Express API.
The issue is I am not setting the headers after the response has been sent anywhere. I am always calling res.status(xxx).json({}) to close ever condition.
Route
const router = require('express').Router();
router.get('/password/validate/:hash', PasswordController.validate);
router.post('/password/update', PasswordController.update);
Controller
This is where the error is occurring. I am calling the validate request specifically.
// Import node packages
const mongoose = require('mongoose');
const Password = require('../models/password');
const User = require('../models/user');
const bcrypt = require('bcryptjs');
const moment = require('moment');
const string = require('../middleware/string_functions')
exports.update = (req, res, next) => {
User.findOne({ email: req.body.email })
.exec()
.then(user => {
if (!user) {
res.status(401).json({
message: 'Cannot retrieve account'
})
}
const expiry = moment().add(30, 'seconds');
const unique_string = string.generate_random(32);
const url_hash = string.base64_encode(unique_string +':'+ user._id);
bcrypt.hash(unique_string, 10, (err, hash) => {
if (err) {
res.status(500).json({
error: err.message
})
}
const query = { user_id: user._id }
const newData = {
hash,
expiry
}
Password.findOneAndUpdate(query, newData, { upsert: true, new: true })
.exec()
.then(request => {
res.status(201).json({
message: 'success',
url: 'localhost:8081/users/password/validate/' + url_hash,
data: request
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
}
exports.validate = (req, res, next) => {
if (!req.params.hash) {
res.status(500).json({
error: 'Missing hash'
})
}
const data = string.base64_decode(req.params.hash).split(':');
console.log(data)
Password.findOne({ user_id: data[1] })
.exec()
.then(request => {
if (!request) {
res.status(404).json({
message: 'Change request not found or expired'
})
}
bcrypt.compare( data[0], request.hash, (err, result) => {
if (err) {
res.status(500).json({
error: err.message
})
}
if (result) {
if (moment().isAfter(request.expiry)) {
res.status(401).json({
message: 'Time has expired'
})
}
res.status(200).json({
message: 'Hash validation successful'
})
}
res.status(500).json({
error: 'Something went wrong'
})
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
}
Console Error
_http_outgoing.js:494
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:494:11)
at ServerResponse.setHeader (_http_outgoing.js:501:3)
at ServerResponse.header (/Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/express/lib/response.js:267:15)
at bcrypt.compare (/Users/chrislloyd/Development/Projects/happy-hour-api/api/controllers/passwords.js:83:22)
at /Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/bcryptjs/dist/bcrypt.js:297:21
at /Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/bcryptjs/dist/bcrypt.js:1353:21
at Immediate.next [as _onImmediate] (/Users/chrislloyd/Development/Projects/happy-hour-api/node_modules/bcryptjs/dist/bcrypt.js:1233:21)
at runCallback (timers.js:789:20)
at tryOnImmediate (timers.js:751:5)
at processImmediate [as _immediateCallback] (timers.js:722:5)
Updated Example
exports.update = (req, res, next) => {
// Check if hash value exists
if (!req.params.hash) {
res.status(500).json({
error: 'Missing hash value'
});
return;
}
// Check if password and confirmation are the same
if (req.body.password != req.body.passwordConfirmation) {
res.status(401).json({
message: 'Password confirmation does not match'
});
return;
}
// Decode and split hash and user id into array
const data = string.base64_decode(req.params.hash).split(':');
// Find record that contains user id
Password.findOne({ user_id: data[1] })
.exec()
.then(request => {
console.log(request)
// Throw 404 error if record is not found
if (!request) {
return res.status(404).json({
message: 'Password change request doest not exist or timed out'
});
}
// Check if change request has expired
if (moment().isAfter(request.expiry)) {
res.status(401).json({
message: 'Password change request expired',
request: {
request: 'http://localhost:3001/users/password/request'
}
});
// Delete expired record
Password.remove({ _id: request._id })
.exec()
.catch(err => {
res.status(500).json({
error: err.message
});
});
return;
}
// Compare hash value from encoded string to encrypted hash value in database
console.log(mongoose.Types.ObjectId(request.user_id))
bcrypt.compare( data[0], request.hash, (err, result) => {
// Bcrypt error performing comparison
if (err) {
res.status(500).json({
error: err.message
});
return;
}
// Check if result is true
if (result) {
// Find user record matching request.user_id and update password
User.findOneAndUpdate({ _id: mongoose.Types.ObjectId(request.user_id) }, {$set: { password: req.body.password }}, {new: true}, (err, user) => {
console.log(user)
// Error finding and updating user record
if (err) {
res.status(500).json({
error: err.message
});
return;
}
// If returned user account is not null
if (user) {
res.status(200).json({
message: 'Password updated',
user
});
return;
}
// Could not find user record
res.status(404).json({
message: 'Could not find user account to update'
});
return;
})
}
// Catch all error
res.status(500).json({
error: 'Something went wrong'
});
return;
})
})
.catch(err => {
res.status(500).json({
error: err.message
});
return;
});
}
That particular error is caused when you send multiple responses to the same request.
You see to be thinking that as soon as you do res.status(...).json(...) that your function returns and stops executing. It does not. res.json() is just a regular function call. It doesn't change the control flow in your function at all (unless it throws an exception). A successful call to res.json() executes and then your function just keeps right on executing the lines of code that follow.
What you need is a return statement after each time you send a response (if there is any other code in your function that could execute and send another response) so that your function doesn't continue to execute and send another response or you could bracket your responses in if/else statements so you don't execute the sending of more than one response.
Here's a fixed version with 5 added return statements to keep the rest of your code from executing after you've sent a response and to keep you from sending multiple responses to the same request. Each addition is commented with ==> added:
// Import node packages
const mongoose = require('mongoose');
const Password = require('../models/password');
const User = require('../models/user');
const bcrypt = require('bcryptjs');
const moment = require('moment');
const string = require('../middleware/string_functions')
exports.update = (req, res, next) => {
User.findOne({ email: req.body.email })
.exec()
.then(user => {
if (!user) {
res.status(401).json({
message: 'Cannot retrieve account'
})
return; // <== added
}
const expiry = moment().add(30, 'seconds');
const unique_string = string.generate_random(32);
const url_hash = string.base64_encode(unique_string +':'+ user._id);
bcrypt.hash(unique_string, 10, (err, hash) => {
if (err) {
res.status(500).json({
error: err.message
})
return; // <== added
}
const query = { user_id: user._id }
const newData = {
hash,
expiry
}
Password.findOneAndUpdate(query, newData, { upsert: true, new: true })
.exec()
.then(request => {
res.status(201).json({
message: 'success',
url: 'localhost:8081/users/password/validate/' + url_hash,
data: request
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
}
exports.validate = (req, res, next) => {
if (!req.params.hash) {
res.status(500).json({
error: 'Missing hash'
})
}
const data = string.base64_decode(req.params.hash).split(':');
console.log(data)
Password.findOne({ user_id: data[1] })
.exec()
.then(request => {
if (!request) {
res.status(404).json({
message: 'Change request not found or expired'
})
return; // <== added
}
bcrypt.compare( data[0], request.hash, (err, result) => {
if (err) {
res.status(500).json({
error: err.message
})
return; // <== added
}
if (result) {
if (moment().isAfter(request.expiry)) {
res.status(401).json({
message: 'Time has expired'
})
}
res.status(200).json({
message: 'Hash validation successful'
})
return; // <== added
}
res.status(500).json({
error: 'Something went wrong'
})
})
})
.catch(err => {
res.status(500).json({
error: err.message
})
})
}
The res object by itself does not stop the execution of your program. You must use return if you prefer to use Guard Clauses instead of Nested Conditions
Replace statements like this:
if (err) {
res.status(500).json({
error: err.message
})
}
With this:
if (err) {
res.status(500).json({
error: err.message
});
return; // return statement added
}

Resources