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! ');
});
Related
1.Can anyone tell me how to allow my error to pass through the app.use('/blogs','blogRoutes') middle ware that scopes my url to a api file?
2.Is the answer something like app.use('/blogs','blogRoutes', next){next(err)}?
const express = require('express');
const morgan = require('morgan');
//use Mongo Db
const mongoose = require('mongoose');
const blogRoutes = require ('./route/blogroutes');
const app = express();
//connect to mongo db
const dBurI = mongo database key
mongoose.connect(dBurI, {useNewUrlParser: true, useUnifiedTopology: true});
.then((result)=> app.listen(3000))
.catch((err)=>console.log(err))
//middleware stack
// allows use of view engine to render - html files in views foles are suffixed with ejs these are found automatically due to views folder beign recognised
app.set('view engine','ejs');
app.use(express.static('public')); //access ppblic folder files - css
app.use(express.urlencoded({extended: true})); //url data and passes into object that can be used on req => req.body
app.use(morgan('dev'));
//redirect route
app.get('/',(req, res, next)=>{
res.redirect('/blogs');
next(err);
});
app.get('/about',(req, res, next)=>{
//send file to a browser
res.render('about', {title: 'About' });
next(err);
});
//redirect 301
app.get('about-me',(req,res, next)=>{
res.redirect('./about');
next(err);
});
//blogroutes
app.use('/blogs','blogRoutes'); //scope all blog urls to blogrouter
// middle ware app.use is called immediately if above are not found - error page 404
app.use((err,req,res)=>{
res.status(404).render('404', {title: '404', error: err });
});
1.after reading the express documentation I believe the answer for espress5+ is as follows:
//redirect route
app.get('/',(req, res, next)=>{
res.redirect('/blogs');
});
app.get('/about',(req, res, next)=>{
//send file to a browser
res.render('about', {title: 'About' });
});
//redirect 301
app.get('about-me',(req,res, next)=>{
res.redirect('./about');
;
});
//blogroutes
app.use('/blogs','blogRoutes',(req,res,next)); //scope all blog urls to blogrouter
// middle ware app.use is called immediately if above are not found - error page 404
app.use((err,req,res, next)=>{
res.status(404).render('404', {title: '404', error: err });
});
2.read this doucmentations and see if im write if not then I believe I have to do this:
//redirect route
app.get('/',(req, res, next)=>{
res.redirect('/blogs');
next(err);
});
app.get('/about',(req, res, next)=>{
//send file to a browser
res.render('about', {title: 'About' });
next(err);
});
//redirect 301
app.get('about-me',(req,res, next)=>{
res.redirect('./about');
next(err);
});
//blogroutes
app.use('/blogs','blogRoutes',(req,res,next)=>{next(err);}); //scope all blog urls to blogrouter
// middle ware app.use is called immediately if above are not found - error page 404
app.use((err,req,res, next)=>{
res.status(404).render('404', {title: '404', error: err });//next would call the express error handler automatically if used here..
});
Following is the error handling behaviour in Express - 4.17:
You do not need to explicitly pass the error to the error handling middleware for synchronized operation. Express will take care of it for you. This can be confirmed by sending a GET request to the / route. In this case, your app does not crash.
If an error occurs during async operations, you must explicitly pass the error to the next middleware using next(). I created two routes to test this behaviour: /async and /async_next. If you visit the /async route, your app should crash because we are not explicitly handling the error. Once you restart your app and navigate to the /async_next route, you will notice that it does not crash and that the error is handled by the custom error handling middleware.
For understanding the above points refer to the following code -
const express = require('express');
const app = express();
app.listen('3001', () => console.log("listening port - 3001"));
app.get('/async', (req, res, next) => {
console.log('Async function');
setTimeout(() => { throw new Error('Async Err from settimeout') }, 1);
})
app.get('/async_next', (req, res, next) => {
console.log('Async function');
setTimeout(() => {
next(new Error('Async Err from settimeout'))
}, 1);
})
app.get('/', (req, res, next) => {
throw new Error('Random Sync Err');
});
app.use((err, req, res, next) => {
console.log('Error from custom handler ', err);
res.send('Error');
});
1.so this seems right but need testing...
//redirect route
app.get('/',(req, res, next)=>{
res.redirect('/blogs');
});
app.get('/about',(req, res, next)=>{
//send file to a browser
res.render('about', {title: 'About' });
});
//redirect 301
app.get('about-me',(req,res,next)=>{
res.redirect('./about');
});
//blogroutes
app.use('/blogs','blogRoutes',(req,res,next)); //scope all blog urls to blogrouter
// middle ware app.use is called immediately if above are not found - error page 404
app.use((err,req,res,next)=>{
res.status(err.status).render('404', {title: 'Error Page', error_message: 'err.message'});
}):
You error handler needs to look like this even with express 5+
function errorHandler (err, req, res, next) {
if (res.headersSent) {
return next(err)
}
res.status(500)
res.render('error', { error: err })
}
You need the err argument to reference to the error...
I followed the Multer code:
app.post('/profile', upload.single('avatar'), function (req, res, next) {
})
One single file should be uploaded. But if one tries to upload multiple files, how to catch the error MulterError: Unexpected field?
I have tried below to no success:
app.post('/profile', upload.single('avatar'), function (req, res, next) {
try {
} catch (error) {
// Why cannot catch any error?
}
})
when upload.single executes next() then only it comes here,
app.post('/profile', upload.single('avatar'), function (req, res, next) {
try {
} catch (error) {
// It catches only errors from above `try block`
}
});
If upload.single faces any error it does not call next() instead it gets passed to next listner. To catch any error of upload.single you must add this after above app.post(/profile).
app.use(function (err, req, res, next) {
var error = err.message;
res.status(500);
res.send({ "error": error });
});
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.
Came accros a sequence of code execution which I found unusual here is the code:
server.js
const Actions_Single_PVC = require('./routes/Actions_single_PVC.js');
app.use('/Actions_single_PVC', Actions_Single_PVC);
app.use((err, req, res, next) => {
console.log('invalid token');
});
Actions_single_PVC.js
router.post('/', asyncMW(async (req, res, next) => {
throw new Error();
}));
router.use((err, req, res, next) => {
console.log('error');
}
And in case you have never seen this construction before here is asyncMW:
const asyncMiddleware = fn =>
(req, res, next) => {
Promise.resolve(fn(req, res, next))
.catch(next);
};
module.exports = asyncMiddleware;
What I didn't understand was that when an error is thrown (I reproduced it here with throw new Error();) that the error handling middleware in the server.js file is executed. I expected that the error handling middleware of the Actions_single_PVC.js would get executed.
Question:
Why is the error middlware in server.js executed and not the error middlware in Actions_single_PVC.js?
It is because the following code applies middleware to only request with base path matching Actions_single_PVC.
app.use('/Actions_single_PVC', Actions_Single_PVC);
Whereas following code is apply middleware to all global requests.
app.use((err, req, res, next) => {
console.log('invalid token');
});
If you'll hit the url /Actions_single_PVC then the middlewares in Actions_single_PVC will get hit.
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