Express next() error - javascript

I'm working with node+express+MongoDB.
I dont understand this error.
When I comment next() it's fine and works but when I use next() I'm getting the error: Error: Can't set headers after they are sent.
videos.route('/')
.get(function(req, res, next) {
Video.find({},function (err,videosCollection) {
if (err)
{
console.log(err);
}
if(!videosCollection.length)
{
console.log("Videos not found");
}
else
{
console.log("videos found");
res.status(200).json(videosCollection);
}
})
// next();
})

next() in express passes async control to the next middlewear in the chain.
This is how next should be used. To pass errors down the chain of middleware.
videos.route('/')
.get(function(req, res, next) {
Video.find({},function (err,videosCollection) {
if (err){
console.log(err);
// pass the error along
next(err);
}else if(!videosCollection.length){
// pass a new error along
next(new Error("Videos noz found"));
}else{
console.log("videos found");
// no need to call next
// res.json finishes the connection
res.status(200).json(videosCollection);
}
})
})

When you use res.status or res.send the request has ended and the function does a soft return. When you do next() you're passing it along in the chain of middleware and endpoints. So basicly, you'll do double return.
So the message tells you that you cant return a response after the response has been returned to the client.
Only when you're writing middleware do you need to use next.

When you call the next function it will call the following middleware after this route.
You are calling this function before the callback is called in Video.find. If you want to call next, you have to do it inside the callback as below.
videos.route('/')
.get(function(req, res, next) {
Video.find({},function (err,videosCollection) {
if (err)
{
console.log(err);
}
if(!videosCollection.length)
{
console.log("Videos not found");
}
else
{
console.log("videos found");
res.status(200).json(videosCollection);
}
next()
})
})

Related

Express Error Handling: Sending a Message to Frontend

I'm having some trouble error handling my authentication API calls. When I send the 500 status from Express, my frontend (Vue in this case) only picks up the message Request failed with status code 500 rather than something more helpful for triage like this is the worst error ever (in the example below).
In the below example, when I call '/post' from the API, I throw an error which is handled by my custom middleware. The middleware successfully handles the error and sends the appropriate status to my frontend, but I can't figure out how to send useful messages (e.g. 'this is the worst error ever') / access them in the front end.
Is this a common use case? Am I doing anything obviously wrong? Does the message I send come up in the (err) parameter, or do I need to add a resp parameter?
Express Route for '/login'
router.post('/login', (req, res, next) => {
throw Error('this is the worst error ever')
})
Custom express error handler
app.use(function(err, req, res, next) {
res.status(err.status || 500).send({
error: {
status: err.status || 500,
message: err.message || 'Internal Server Error',
},
});
});
Handle the API Response in Vue
login (e) {
e.preventDefault();
UserService.login(this.username, this.password) //this is simple axios post call
.catch((err) => {
this.loginStatus = err.message
return
})
}
Found the answer to this for those that find this helpful. The err that is caught has a response variable. This is where the data is sent via the express send command. See corrected code below for the frontend:
login (e) {
e.preventDefault();
UserService.login(this.username, this.password) //this is simple axios post call
.catch((err) => {
this.loginStatus = err.response.data.message
return
})
}
I think you need to add:
Throw new Error()
instead of
Throw Error
If you are making an asynchronous calling you can do this
app.get('/', function (req, res, next) {
fs.readFile('/file-does-not-exist', function (err, data) {
if (err) {
next(err) // Pass errors to Express.
} else {
res.send(data)
}
})
})
Code should look like this:
router.post('/login', (req, res, next) => {
throw new Error('this is the worst error ever')
})
Check this in express documentation

Error Handling in Strongloop Loopback

I know the difference between a callback and a middleware next() function.
If a write a custom remote-method in Loopback, I can easily send errors in callback e.g callback(error,null) but in remote hooks or observers whenever I send error in next() function e.g
var err = new Error('This is error');
next(err)
it always says that Internal server error but it does not tell me what error is.
In order to view error I have to login to server and view logs.
Please tell me how can I send error as a response in next() function so that the on frontend I know what error has occurred.
Maybe use a middleware to hook in:
app.use( function(err,req,res){
res.json(err);
});
(This needs to he the last middleware defined...)
basically you can define callbacks with err and result.
For example in loopback,
if I have a model call "Action" you can simply send err or result to front end using json.
app.get('/your/api/call', function (req, res, next) {
var getTeam = function (cb) {
app.models.Team.find({}, function (err, teams) {
if (err) {
cb(err);
} else {
cb(null, teams);
}
});
};
async.waterfall([
getTeam
], function (err, team, role) {
if (err){
res.send(err); //send error to front end
} else {
res.send(team); //send result to front end
}
});
});
This approach can use with "app.use" function in root level also.

hook object in error handler feather js

I have the following situation, i have a middleware that add a flag when a user is logging
//if some situation happend
req.feathers.isAuthenticated = true;
//else
req.feathers.isAuthenticated = false;
next();
and i have a hook that check if a user is already logged in some services
myService.before({
create(hook, next) {
if (!hook.params.isAuthenticated) {
throw new Error('AccessDenied');
}
next();
}
});
this work as expected, the problem is on the error handler, when i add a simple error handler to the end of my app
app.use(function (err, req, res, next) {
if (isDev) {
console.error(err);
}
res.status(err.status || 500);
res.json(err);
});
The err object is the entire hook object, that is an instance of Error too
i just want to get the error that a throw before on the hook, i try calling next(err) on the hook but this not work.
Some one can help me with this please?
EDIT
I would like to not delete the hook property on my error handler
When you call next(error) you also have to return at the same time so that next isn't called again:
myService.before({
create(hook, next) {
if (!hook.params.isAuthenticated) {
return next(new Error('AccessDenied'));
}
next();
}
});
If that also does not work please file an issue in feathers-hooks.

Creating Express param middleware that updates the request object

Im trying to update the req.conversation before its handled by another function called read. I know the middleware is being called before read but when I log the req.conversation object in read it doesnt reflect the updates made in the middleware.
/**
* Conversation middleware
*/
exports.conversationByID = function(req, res, next, id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(400).send({
message: 'Conversation is invalid'
});
}
Conversation.findById(id).populate('user', 'displayName').populate('readers', 'displayName').exec(function(err, conversation) {
if (err) return next(err);
if (!conversation) {
return res.status(404).send({
message: 'Conversation not available'
});
}
req.conversation = conversation;
next();
});
};
Where is the id parameter in your middleware callback coming from? If it's a url param (e.g. /conversations/:id) it should be req.params.id.

Middlware shared by errors and normal chain

I'm trying to have a piece of middleware that will establish a variable within the chain of err and non error. How is this possible? Passing err in that callback automatically makes it skip over the normal chain of middleware, and vise-versa, if I remove err it skips over the err chain of middleware...
middleware.redirect = function(){
return function (err, req, res, next){
if(req.form.redirect){
req.form_redirect = url.parse(req.form.redirect);
}else{
req.form_redirect = url.parse(config.domain);
req.form_redirect.pathname = "thanks";
}
if(err) return next(err);
return next();
}
}
The error middleware, the one with the signature (err, req, res, next) should be the final destination for your route. If you want to add to the req object, this needs to be done before an error is thrown or next(new Error()) is called.

Categories

Resources