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.
Related
i'm working on node.js using Express to built a backend.
i'm intended to handle status 500 error that may happened.
router.put('/test', async (req, res) => {
try {
return res.send(await request.updateTest(req.body, 1))
} catch(err) {
console.log(err)
return res.status(500).send(err.stack)
}
})
this is my example of the code. it's do work perfectly. but when i'm try to make unknown error from the database query, i want to log the error and return status 500 as response with the error detail.
but i'll need to add try and catch every time i'm build a new controller/routes
is there anyway i could express them in form of middleware instead of write try and catch everytime?
this is an example of code i've try to make it as middleware but it's has no work and no effect when called.
error.js
module.exports = function (err, req, res, next) {
console.log(err)
res.status(500).send({
error: 'Internal Server Error',
message: err.stack
})
next(err)
}
main.js
const errorHandler = require('./error')
const { corsOption } = require('./cors')
const cors = require('cors')
const test = require('./test')
module.exports = function (app) {
app.use(cors(corsOption))
app.use(errorHandler)
app.use('/api/test', test)
}
is there anyway that i can do for this to work?
Your global error handler should be placed after all other middlewares/routes:
app.use(middleware)
// all other middlewares
app.use('/api/test', test)
// all other routes
// error handler
app.use(function (err, req, res, next) {
res.status(500).json({
error: err.message,
});
});
To avoid adding try/catch to everything, better to wrap your route handler to catch the errors (asyncWrapper):
app.use(middleware)
// all other middlewares
const asyncWrapper = (cb) => {
return (req, res, next) => cb(req, res, next).catch(next);
};
const test = async (req, res) => {
return res.send(await request.updateTest(req.body, 1))
}
// wrap your handler to catch errors (Async functions return a promise)
app.use('/api/test', asyncWrapper(test))
// all other routes
// error handler
app.use(function (err, req, res, next) {
res.status(500).json({
error: err.message,
});
});
There are two approaches to resolve unhandled exceptions in Node.js
Using try-catch blockwhich is already you are using
Using Process i.e use Process to handle exception. A process is a global object that provides information about the current Node.js process. The process is a listener function that is always listening to the events. The most effective and efficient approach is to use Process. If any uncaught or unhandled exception occurs in your code flow, that exception will be caught in code
process.on('uncaughtException', function(err) {
// Handle the error safely
console.log(err)
})
The above code will be able to handle any sort of unhandled exception which occurs in Node.js. see this Process Events
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.
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()
})
})
I just started a project using Express and I have no real knowledge in node.js, and even in Javascript in general. I was wondering what was the proper way of throwing and catching errors so that they display correctly, and also so that I don't duplicate too much code. I thought this bit of code in app.js:
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
acted like a big catch that would intercept all the errors I would throw in my controllers. But I don't really know how to make it work. For example, let's take this bit of code in users.js:
/* GET users listing. */
router.get('/', function(req, res, next) {
connection.query('SELECT id, name FROM user', function(err, rows, fields) {
if (err) throw err;
res.render('users', {
title: 'Users',
userList: rows
});
});
});
How do I send something like a 204 code (No Content)
How do I report an error with the database
Any help/hint would be appreciated, I'll keep looking on forums and stuff in the meantime.
Express uses a series of middleware to handle the request. If the route matches and defined route it will handle it. Otherwise, you can put '/404' route at last after importing all the routes. It will automatically reach there when no route is found. Else if you don't want to send a response you can use next() so that it moves to next middleware and ultimately to '/404' middleware.
/* GET users listing. */
router.get('/', function(req, res, next) {
connection.query('SELECT id, name FROM user', function(err, rows, fields) {
if (err) {
return res.status(502).json({message:'db error'});
};
res.render('users', {
title: 'Users',
userList: rows
});
});
});
Thank you all for your answers. What I was looking for (and found) was the next(error) function to pass control to the error handler located in app.js (Cf. http://expressjs.com/en/guide/routing.html for more details).
You can give a relevant message with statusCode like this
/* GET users listing. */
router.get('/', function(req, res, next) {
connection.query('SELECT id, name FROM user', function(err, rows, fields) {
if (err){
res.status(500).send("Something is not right");
};
//if you get rows of array type, then you can do this for empty records
else if(rows.length===0){
res.status(204).send('No records found!')
}else{
res.render('users', {
title: 'Users',
userList: rows
});
}
});
});
In Express, each route handler is passed a 'res' parameter, that is used to provide the response to the client. Sample usage of creating a response with a specific code, code error and empty body
router.get('/', function(req, res, next) {
res.status(401, "Authentication mismatch").json({});
});
Instead of json() you can also use send() to send a plain text back.
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.