I am trying to create middleware to handle the response that are next()ed from the routes, but it bypasses route.use and throws 404
const router = require('express').Router();
const { errorResponse, successResponse, redirectResponse } = require('./test');
const errorResponse = (err, req, res, next) => {
next(Boom.notFound());
};
const successResponse = (err, req, res, next) => {
res.locals.res = {
data: {
hello: 'world'
}
};
next();
};
const redirectResponse = (err, req, res, next) => {
res.locals.res = {
meta: {
redirect: true
}
};
next();
};
module.exports = (app) => {
/**
* Test Routes
*/
router.get('/successTest', successResponse);
router.get('/errorTest', errorResponse);
router.get('/redirectTest', redirectResponse);
router
.use((err, req, res, next) => {
console.log('successHandler');
next();
})
.use((err, req, res, next) => {
console.log('redirectHandler');
next();
})
.use((err, req, res, next) => {
console.log('errorHandler');
res.status(200).json({});
});
// does not go to any of the middlewares and gives out 404
// from digging in i found that err param is not err but is req
app.use('/v1', router);
};
Thanks for helping
Take a look at Express.js Error-handling middleware documentation.
Basically it says that middleware with 4 arguments like
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
interpreted as middleware to handle errors.
It means that it won't act like regular middleware.
For example:
app.get('/1',
(err, req, res, next) => {
// will not be outputted in console
console.log('got here');
next();
},
(req, res) => {
res.send('Hello World!');
});
app.get('/2',
(req, res, next) => {
console.log('got here');
next();
},
(req, res) => {
res.send('Hello World!');
});
Related
So my routes are ordered like shown bellow
verifyToken middleware is being used in a lot of routes.
Generally if an error occurs i want the global error handler of index.js to handle it.
But if the error occurred while verifyToken middleware is being used by the login.html route with method = get i would like
to handle it inside routers/user.js which i thought i could do by using router.get(/\/login(\.html)?$/, (error, req, res, next) => {} but the error bypasses it and moves to global error handler.
index.js
const userRouter = require('./routers/user')
app.get('', (req, res) => {
res.render('index')
})
app.use(userRouter)
app.use((req, res, next) => {
res.status(404).redirect('/404.html');
})
//Global error handling
app.use( (error, req, res, next) => {
switch(error.name) {
case "UnauthorizedError":
console.log("UnauthorizedError = ", error.message)
res.status(401).redirect('/401.html');
break
case "InternalServerError":
console.log("InternalServerError = ", error.message)
res.status(500).send('whatever')
break
default:
console.log("Another error = ", error)
}
})
/routers/user.js
const verifyToken = require('../middleware/authentication/verifyToken')
router.get(/\/login(\.html)?$/, verifyToken, (req, res) => {
// If he is already logged in redirect him to dashboard
// This route works as expected
res.redirect('/admin/dashboard.html')
});
router.get(/\/login(\.html)?$/, (error, req, res, next) => {
// If error = Unauthorized
// which means that he is not logged in proceed
if(error.name === 'UnauthorizedError') res.render('login')
// else pass error to global error handler (at index.js)
else next(error)
});
module.exports = router
/middleware/authentication/verifyToken.js
const jwt = require('jsonwebtoken')
var createError = require('http-errors')
const verifyToken = async (req, res, next) => {
try {
// Do some stuff
if (token_doesnt_exist) return next(createError(401, 'TOKEN NOT FOUND', {expose: false}))
// Do some stuff
next()
} catch {
next(createError(e.status, e.message, {expose: false}))
}
})
module.exports = verifyToken
UPDATE
I ended up transforming
router.get(/\/login(\.html)?$/, (error, req, res, next) => {}
to
router.use((error, req, res, next) => {}
which i guess works since it only catches errors from the above route.
I'm not sure if this is the best way i'd really like to see an alternative.
const verifyToken = require('../middleware/authentication/verifyToken')
router.get(/\/login(\.html)?$/, verifyToken, (req, res) => {
// If he is already logged in redirect him to dashboard
// This route works as expected
res.redirect('/admin/dashboard.html')
});
router.use((error, req, res, next) => {
// If error = Unauthorized
// which means that he is not logged in proceed
if(error.name === 'UnauthorizedError') res.render('login')
// else pass error to global error handler (at index.js)
else next(error)
});
module.exports = router
Since you want to catch errors ONLY in that route you can catch the error in the middleware itself:
const verifyToken = async (req, res, next) => {
try {
//middleware logic
} catch(err) {
//error handling logic
}
Maybe not SUPER elegant but it works..
I have to routes that I currently do like this:
app.all('*', passport.authenticate('facebook-token', { session: false }));
//Here goes specific routes.
app.get('/user/me',
(req, res, next) => {
next();
});
app.get('/user/makeRider',
(req, res, next) => {
req.user.user.makeRider(req.query)
.then((user) => {
next();
});
}
);
app.all('*', (req, res) => {
req.user.user.full().then((fulluser) => {
res.json({
user: fulluser,
params: req.query
});
});
});
They are responsible for authentification and output in my REST-api. The problem with these routes is that they make all routes valid, never throwing 404:s. Is there a better way of doing this, without adding the functions to every route?
This is not a setup that is common to Express (Restify has an option where you can call next() to transfer the request to a specific route, which would be your output handler, but that has its limitations as well).
Here's a possible workaround.
First, declare a output middleware:
let outputMiddleware = (req, res) => {
req.user.user.full().then((fulluser) => {
res.json({
user: fulluser,
params: req.query
});
});
};
Next, store a reference to the Passport middleware:
let authenticateMiddleware = passport.authenticate('facebook-token', { session: false });
And create a wrapper function to chain all middleware functions together:
let chain = (fn) => [ authenticateMiddleware, fn, outputMiddleware ];
Lastly, declare your routes like this:
app.get('/user/me', chain((req, res, next) => {
next();
}));
What this does is basically create route handlers that look like this:
app.get('/user/me', [
passport.authenticate(...),
(req, res, next) => { ...; next() },
(req, res) => { ...; res.json(...) }
]);
Bookshelf transaction is working only in callback function. How i can do it?
var express = require('express');
var router = express.Router();
router.post('/', (req, res, next) => {
Bookshelf.transaction((trx) => {
req.trx = trx;
next();
});
});
router.post('/', (req, res, next) => {
// use req.trx
});
router.post('/', (req, res, next) => {
// use req.trx
});
router.post('/', (req, res, next) => {
req.trx.commit();
});
Here is the example:
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
//code
});
app.post('/user/register', function(req, res) {
//code
})
app.put('/user/register', validateToken, function(req, res) {
//code
})
app.delete('/user/delete', validateToken, function(req, res) {
//code
})
If I have 10 api that need validToken, I should add validToken middleware 10 times, like:
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
....
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
How can I group api by using the same middleware?
Here's how to re-use the same callback function for multiple routes (like middleware):
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
// code
});
app.post('/user/register', function(req, res) {
// code
});
// Be sure to specify the 'next' object when using more than one callback function.
app.put('/user/register', validateToken, function(req, res, next) {
// code
next();
});
app.delete('/user/delete', validateToken, function(req, res, next) {
// code
next();
});
Also, you can replace app.METHOD (e.g. .post, .get, .put, etc.) with app.all and your callback will be executed for any request type.
Just wrong, so do not put into mass participation of the (Google translated from: 刚才看错了,改成这样就不用放进传参了)
var group = {url:true,url:true,url:true};
app.use(function(req,res,next){
if(group[req.url]){
// Do something with request here
next();
} else {
next();
}
})
What should I use:
express.Router().route()
or
express.route()
?
Is it true express.Router().route() is someway deprecated?
For the current version of Express, you should use express.Router().route(). See the express documentation for confirmation. express.Router().route() is not depreciated.
For example:
var router = express.Router();
router.param('user_id', function(req, res, next, id) {
// sample user, would actually fetch from DB, etc...
req.user = {
id: id,
name: 'TJ'
};
next();
});
router.route('/users/:user_id')
.all(function(req, res, next) {
// runs for all HTTP verbs first
// think of it as route specific middleware!
next();
})
.get(function(req, res, next) {
res.json(req.user);
})
.put(function(req, res, next) {
// just an example of maybe updating the user
req.user.name = req.params.name;
// save user ... etc
res.json(req.user);
})
.post(function(req, res, next) {
next(new Error('not implemented'));
})
.delete(function(req, res, next) {
next(new Error('not implemented'));
})
Router.route() can use for chainable routes.
Meaning: You have one API for all the METHODS, you can write that in .route().
var app = express.Router();
app.route('/test')
.get(function (req, res) {
//code
})
.post(function (req, res) {
//code
})
.put(function (req, res) {
//code
})