I saw a lot of post but I didn't understand how can I handle the error
I Have these middleware
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.use(function (err, req, res, next) {
res.render('error', {
message: err.message,
error: err
});
});
And these middleware manage when I get 404 Page
Inside my routes I have for example:
app.route('/post/delete/:id_post')
.get(function (req, res,next) {
if(req.params.id_post !=req.decoded._id){
var err = new Error('Error 500, you don\t have access');
next(err);
}
Post.find({_id:req.params.id_post},function(err, post) {
if (err) throw err;
res.redirect('/');
});
});
How I have to manage error inside if(req.params.id_post !=req.decoded._id) and the error after Query on Db?
You can use middleware to catch error on routes like
app.get('/post/delete/:id_post',function(req,res,next){
if(req.params.id_post !=req.decoded._id){
var err = new Error('Error 500, you don\t have access');
return next(err);
}
Post.find({_id:req.params.id_post},function(err, post) {
if (err) return next(err);
res.redirect('/');
});
},function(err,req,res,next){
//you can handle all your errors thrown from ahead middleware
})
Related
Is there a way to add middleware or app.use() to catch all possible errors?
I have tried some global try-catch approaches but it looks so fragile.
You can handle your errors like this:
res.status(500).send({ msg: 'Wrong email' })
And you can change the status code to send different type of errors or responses:
res.status(404).send({ msg: 'Not found' })
res.status(200).send({ msg: 'successful' })
My approach would be like below
Place below code in
server.js
or index.js
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
app.all('*', (req, res, next) => {
next(new AppError(`Can't find ${req.originalUrl} on this server!`, 404));
});
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
res.status(err.statusCode).json({
status: err.status,
message: err.message
});
});
app.use((req, res, next) => {
console.log("Middleware 1 called.")
console.log(req.path)
next() // calling next middleware function or handler
})
app.get('/', (req, res) => {
console.log("Route handler called.")
res.send("Hello world!") // response sent back – no more middleware called
})
setting
app.use("/api/tobaccos", tobaccos);
app.use(function(err, req, res, next) {
console.error(err.message);
});
api:
router.get("/:id", async (req, res) => {
console.log("GET TOBACCO:" + req.params.id);
await Tobacco.findById(req.params.id)
.then(tobacco => res.status(200).json({ status: "success", data: tobacco }))
.catch(error => res.status(404).json({
status: "fail",
msg: "Tobacco not found!",
code: "error.tobaccoNotFound"
}));
});
I'm trying to add middleware for all 404 errors
app.use(function(err, req, res, next) {
console.error(err.message);
});
or this doesn't work
app.get('*', function(req, res){
res.status(404).send('what???');
});
What is wrong?
In Express, 404 responses are not the result of an error, so the error-handler middleware will not capture them. This behavior is because a 404 response simply indicates the absence of additional work to do; in other words, Express has executed all middleware functions and routes, and found that none of them responded. All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response:
app.use(function (req, res, next) {
res.status(404).send("Sorry can't find that!")
})
Add routes dynamically at runtime on an instance of express.Router() so the routes are not superseded by a middleware function.
Reference: https://expressjs.com/en/starter/faq.html
You can add this middleware in your root file. It sends error for any invalid routes.
//Handles 404 errors
app.use((req, res, next) => {
const error = new Error('Error Occured');
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
Alternatively, you can try which captures all 404 errors
app.use(function(req, res, next) {
res.status(404).send( 'Error Occured! ');
});
Last time I used passport authenticate for login in the following manner:
router.post('/login', parserUrlEncodedTrue, (request, res, next) => {
console.log('logging in user');
passport.authenticate('local', (err, user, info) => {
var options = "";
if(err){
return next(err);
}
if(!user){
return res.json({
error: true,
message: "User doesn't exist"
});
}
req.logIn(user, function(err) {
if (err){
return next(err);
}
return res.json({
error: false,
message: "Login Success"
});
});
})(req, res, next);
Now I'm trying to use formidable.js and it works fine for registration but can't make it work with login.
let form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if(err){
helpers.errors(err, res);
} else {
passport.authenticate('local', (err, user, info) => {})(req, res, next);
}
});
passport.authenticate gets to req before it is parsed by formidable. I'm also using express and passport-local-mongoose.
Here's my application structure:
- app.js
- routes
---- index.js
The ExpressJS app creates error handlers for development and production environments. Here's a code snippet from app.js:
app.use('/', routes); // routing is handled by index.js in the routes folder
//The following middleware are generated when you create the Express App
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// 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.ejs', {
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: {}
});
});
And inside of routes/index.js, where I handle all the routing:
var router = express.Router();
router.get('/', function (req, res) {
someAsyncFunction(function(err, result) {
if (err) throw err; // Handle this error
}
});
module.exports = router;
I want the err to be passed to one of the error handlers instead of being thrown. How can I do this?
You have to pass it to the next callback which is usually the third parameter in the route handler
var router = express.Router();
router.get('/', function (req, res, next) {
someAsyncFunction(function(err, result) {
if (err) {
next(err); // Handle this error
}
}
});
module.exports = router;
calling next(err) will allow the error to be caught in a middleware down the chain with the following signature:
app.use(function (err, req, res, next){
// do something about the err
});
Reference: http://expressjs.com/en/guide/error-handling.html
You can also create a middleware function to handle error in all routes without copying code everywhere, using arrow functions if you like.
1) Create a const function to handle errors.
either:
const handleErrorAsync = func => (req, res, next) => {
func(req, res, next).catch((error) => next(error));
};
or
const handleErrorAsync = func => async (req, res, next) => {
try {
await func(req, res, next);
} catch (error) {
next(error);
}
};
2) In your router use it for every request:
var router = express.Router();
router.get('/req1', handleErrorAsync(async (req, res, next) => {
let result = await someAsyncFunction1();
if(result){
// res.send whatever
}
}));
router.post('/req2', handleErrorAsync(async (req, res, next) => {
let result = await someAsyncFunction2(req.body.param1);
if(result){
// res.send whatever
}
}));
router.post('/req3', handleErrorAsync(async (req, res, next) => {
let result = await someAsyncFunction3(req.body.param1, req.body.param2);
if(result){
// res.send whatever
}
}));
module.exports = router;
3) In your server main app handle error:
// 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.ejs', {
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: {}
});
});
This way you can reuse the error handling function in any route. Also, if there are any unhandled errors in any of your functions, this will catch them as well.
Try catch error handling taken from Here
I want to catch the error from the bodyParser() middleware when I send a json object and it is invalid because I want to send a custom response instead of a generic 400 error.
This is what I have and it works:
app.use (express.bodyParser ());
app.use (function (error, req, res, next){
//Catch bodyParser error
if (error.message === "invalid json"){
sendError (res, myCustomErrorMessage);
}else{
next ();
}
});
But this seems to me a very ugly approach because I'm comparing the error message which could change in future express versions. There's any other way to catch bodyParser() errors?
EDIT:
This is the error when the request body has an invalid json:
{
stack: 'Error: invalid json\n at Object.exports.error (<path>/node_modules/express/node_modules/connect/lib/utils.js:55:13)\n at IncomingMessage.<anonymous> (<path>/node_modules/express/node_modules/connect/lib/middleware/json.js:74:71)\n at IncomingMessage.EventEmitter.emit (events.js:92:17)\n at _stream_readable.js:872:14\n at process._tickDomainCallback (node.js:459:13)',
arguments: undefined,
type: undefined,
message: 'invalid json',
status: 400
}
Pretty printed stack:
Error: invalid json
at Object.exports.error (<path>/node_modules/express/node_modules/connect/lib/utils.js:55:13)
at IncomingMessage.<anonymous> (<path>/node_modules/express/node_modules/connect/lib/middleware/json.js:74:71)
at IncomingMessage.EventEmitter.emit (events.js:92:17)
at _stream_readable.js:872:14
at process._tickDomainCallback (node.js:459:13)
I think your best bet is to check for SyntaxError:
app.use(function (error, req, res, next) {
if (error instanceof SyntaxError) {
sendError(res, myCustomErrorMessage);
} else {
next();
}
});
From the answer of #alexander but with an example of usage
app.use((req, res, next) => {
bodyParser.json({
verify: addRawBody,
})(req, res, (err) => {
if (err) {
console.log(err);
res.sendStatus(400);
return;
}
next();
});
});
function addRawBody(req, res, buf, encoding) {
req.rawBody = buf.toString();
}
what I did was just:
app.use(bodyParser.json({ limit: '10mb' }))
// body parser error catcher
app.use((err, req, res, next) => {
if (err) {
res.status(400).send('error parsing data')
} else {
next()
}
})
Ok, found it:
bodyParser() is a convenience function for json(), urlencoded() and multipart(). I just need to call to json(), catch the error and call to urlencoded() and multipart().
bodyParser source
app.use (express.json ());
app.use (function (error, req, res, next){
//Catch json error
sendError (res, myCustomErrorMessage);
});
app.use (express.urlencoded ());
app.use (express.multipart ());
All errors include a type property from 1.18.0 release onwards. For parse failure, err.type === 'entity.parse.failed'.
app.use(function (error, req, res, next) {
if (error.type === 'entity.parse.failed') {
sendError(res, myCustomErrorMessage);
} else {
next();
}
});
I found checking for SyntaxError to be not enough, therefore I do:
if (err instanceof SyntaxError &&
err.status >= 400 && err.status < 500 &&
err.message.indexOf('JSON') !== -1) {
// process filtered exception here
}
create new module "hook-body-parser.js"
hook everything with body parser over here
const bodyParser = require("body-parser");
module.exports = () => {
return [
(req, res, next) => {
bodyParser.json()(req, res, (error) => {
if (error instanceof SyntaxError) {
res.sendStatus(400);
} else {
next();
}
});
},
bodyParser.urlencoded({ extended: true }),
];
};
and use over express like this
...
app.use(hookBodyParser())
...
if you want to catch all errors thrown by body-parsr for example
entity.too.large or encoding.unsupported
just place this middleware right after your body-parser initialization
$ npm i express-body-parser-error-handler
https://www.npmjs.com/package/express-body-parser-error-handler
for example:
const bodyParserErrorHandler = require('express-body-parser-error-handler')
const { urlencoded, json } = require('body-parser')
const express = require('express')
const app = express();
router.route('/').get(function (req, res) {
return res.json({message:"🚀"});
});
// body parser initilization
app.use('/', json({limit: '250'}));
// body parser error handler
app.use(bodyParserErrorHandler());
app.use(router);
...
(bodyParser, req, res) => new Promise((resolve, reject) => {
try {
bodyParser(req, res, err => {
if (err instanceof Error) {
reject(err);
} else {
resolve();
}
});
} catch (e) {
reject(e);
}
})
Bullet-proof. Future-aware. WTFPL-Licensed. And also useful w/ async/await.