9/ Errors
Handling Errors
-
Express has a default error handling
-
Errors can also be thrown too:
throw new Error('Pass required');
-
Writing error handlers function(error, req, res, next). If an error is thrown anywhere this function will run
app.use((err, req, res, next)=>{
console.log('Error');
})
- define error class in Express
class AppError extends Error{
constructor (message, status){
super();
this.message = message;
//express default error handling is looking
//for a property called status
this.status = status;
}
}
module.exports = AppError;
const veryPassaword = (req, res, next)=>{
const {password} = req.query;
//http://localhost:3000/?password=test
if (password === 'test'){
next();
}
throw new AppError('password required', 401);
};
- destructuring the error
app.use((err, req, res, next)=>{
const {status = 500, message = 'Something wrong'} = err;
res.status(status).send(message)
})
Async errors
-
Error caused by looking for an id that does not exist in the database
-
If the function is async, the error handler has to be passed inside the next() parameters
app.get('/products/:id', async (req, res, next) => {
const {id} = req.params;
const product = await Product.findById(id);
if (!product){
return next(new AppError('Product not found', 404));
}
//without return this code will still try run (response is given by the error handler
//but Cannot read property 'name' of null will be in the node console log)
res.render('products/show', {product})
})
Errors from Mongoose or Users
- use
try-catch
(only with async functions)
app.post('/products', async (req, res, next) =>{
try{
const newProduct = new Product(req.body)
await newProduct.save();
console.log(newProduct);
res.redirect(`/products/${newProduct._id}`);
}
catch(e){
next(e);
}
})
- use
try-catch
when throwing an error too:
app.get('/products/:id', async (req, res, next) => {
try{
const {id} = req.params;
const product = await Product.findById(id);
if (!product){
throw new AppError('Product not found', 404);
}
res.render('products/show', {product})
}
catch(e){
next(e);
}
})
Defining an async utility
function wrapAsync(fn) {
return function(req, res, next){
fn(req, res, next).catch(e=>next(e));
}
}
app.get('/products/:id', wrapAsync(async (req, res, next) => {
const {id} = req.params;
const product = await Product.findById(id);
if (!product){
throw new AppError('Product not found', 404);
}
res.render('products/show', {product});
}))
- Express 5 is able to handle errors in async functions
Differentiating Mongoose errors
- Errors can be of different categories (Validation error, Cast error…)
app.use((err, req, res, next)=>{
console.log(err.name);
next(err);
})
- we can have some logic for all the errors of a specific category
const handleValidationError = err => {
//console.log(err);
return new AppError(`Validation Failed: ${err.message}`,400);
}
app.use((err, req, res, next)=>{
console.log(err.name);
if (err.name ==='ValidationError'){
err = handleValidationError(err); //returns Validation Failed: Validation failed: name: name cannot be blank
}
next(err);
})
and in the product schema:
name: {
type: String,
required: [true, 'name cannot be blank']
},
Written on January 2, 2022