How do i handle Errors in node express app? - javascript

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
})

Related

How add middleware for 404 errors on express

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! ');
});

receiveing 404 error when trying to send a POST request

im trying to setup an API using node.js and in my app.js class im handling request errors where i return a 404 in case something goes wrong, now thats my problem, i can't see how am i requesting anything wrong, i am still receiving 404 error, im trying to send a post request to my API exactly like this:
{
"name":"Harry Potter 5",
"price":"12.99"
}
then i get this
Here's my app.js
const express = require('express');
const app = express();
const morgan = require('morgan');
const productRoutes = require('./api/routes/product');
const orderRoutes = require('./api/routes/order');
const bodyParser = require('body-parser');
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({
extended:false
}));
app.use(bodyParser.json());
app.use((req, res, next) => {
const error = new Error("Not found");
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
app.use('/products', productRoutes);
app.use('/orders', orderRoutes);
module.exports = app;
Here's my product.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
res.status(200).json({
message: 'Handling GET requests to /products'
});
});
router.post('/', (req, res, next) => {
const product = {
name: req.body.name,
price: req.body.price
};
res.status(201).json({
message: 'Handling POST requests to /products',
createdProduct: product
});
});
router.get('/:productId', (req, res, next) => {
const id = req.params.productId;
if (id === 'special') {
res.status(200).json({
message: 'You discovered the special ID',
id: id
});
} else {
res.status(200).json({
message: 'You passed an ID'
});
}
});
router.patch('/:productId', (req, res, next) => {
res.status(200).json({
message: 'Updated product!'
});
});
router.delete('/:productId', (req, res, next) => {
res.status(200).json({
message: 'Deleted product!'
});
});
module.exports = router;
It's because you are setting everything to error out :)
See the documentation from here - from the provided link:
Writing error handlers Define error-handling middleware functions in
the same way as other middleware functions, except error-handling
functions have four arguments instead of three: (err, req, res, next).
For example:
// pay attention to err param
app.use(function (err, req, res, next) {
console.error(err.stack)`
res.status(500).send('Something broke!')
})
In your code you have this bit:
app.use((req, res, next) => {
const error = new Error("Not found");
error.status = 404;
next(error);
});
which tells express that every request should be responded with a 404. You should either make it a proper error handler, or remove it.
This is because any request execute the 404 handler.
Look at this shorten version of your code:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended:false
}));
app.use(bodyParser.json());
app.use((req, res, next) => {
console.log("Got into 404 handler");
const error = new Error("Not found");
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
console.log("Got into 500 handler");
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
app.use('/products', (req, res, next) => {
console.log("Got into 200 handler");
res.status(200).end();
});
app.listen(8080);
It prints "Got into 404 handler" at each request. Now, if you comment out the 404 callback this way: all requests go through the 500 and 200 callbacks:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended:false
}));
app.use(bodyParser.json());
/* there used to be the 404 callback here */
app.use((error, req, res, next) => {
console.log("Got into 500 handler");
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
app.use('/products', (req, res, next) => {
console.log("Got into 200 handler");
res.status(200).end();
});
app.listen(8080);
Now in your specific problem, the code below would work (I just swapped the order of the handlers):
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended:false
}));
app.use(bodyParser.json());
app.use('/products', (req, res, next) => {
console.log("Got into 200 handler");
res.status(200).end();
});
app.use((req, res, next) => {
console.log("Got into 404 handler");
const error = new Error("Not found");
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
console.log("Got into 500 handler");
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
app.listen(8080);
Hope this helps.

Node.js (Express) error handling middleware with router

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

Error Handle in Express 4

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
})

Catch express bodyParser error

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.

Categories

Resources