Catch all route EXCEPT for /login
I am currently writing an API which will require a user to pass an authentication token in the header of each request. Now I know I can create a catchall route say
app.get('/*', function(req,res){
});
but I was wondering how do I make it so that it excludes certain routes such as /login
or /
?
I'm not sure what you want to happen when a user accesses /login
or /
, but you can create separate routes for those; if you declare them before the catch-all, they get first dibs at handling the incoming requests:
app.get('/login', function(req, res) {
...
});
app.get('/', function(req, res) {
...
});
app.get('*', function(req, res) {
...
});
You can always place catch-all route after the ones you want to exclude (see robertklep answer).
But sometimes you simply don't want to care about the order of your routes. In this case you still can do what you want:
app.get('*', function(req, res, next) {
if (req.url === '/' || req.url === '/login') return next();
...
});
If you want to validate credentials or authenticity in every request you should use Express Routing feature "all", you can use it like this:
app.all('/api/*', function(req, res, next){
console.log('General Validations');
next();
});
You could place it before any Routing stuff.
Note that in this case I used "/api/" as path, you can use "/" you it fits your needs.
Hope it is not too late to help somebody here.
Another way to make a catch-all route handler is this:
app.get('/login', function(req, res) {
//... login page
});
app.get('/', function(req, res) {
//...index page
});
app.get('/:pageCalled', function(req, res) {
console.log('retrieving page: ' + req.params.pageCalled);
//... mypage.html
});
This works exactly like robertklep's (accepted) answer, but it gives you more information about what the user actually requested. You now have a slug req.params.pageCalled
to represent whatever page is being requested and can direct the user to the appropriate page if you have several different ones.
One gotchya to watch out for (thx @agmin) with this approach, /:pageCalled
will only catch routes with a single /
, so you will not get /route/1
, etc. Use additional slugs like /:pageCalled/:subPageCalled
for more pages (thx @softcode)
Negative lookahead regex
Maybe this will come handy at times:
const app = require('express')()
app.get(/^\/(?!login\/?$)/, (req, res) => { res.send('general') })
app.get('*', (req, res) => { res.send('special') })
app.listen(3000)
With this, you would get:
/ general
/asdf general
/login special
/login/ special
/login/asdf general
/loginasdf general
Or if you also want /login/asdf
to be special
:
app.get(/^\/(?!login($|\/.*))/, (req, res) => { res.send('general') })
In particular, when I Googled here I was thinking about the case of serving static frontend files on the same server that does the API for a SPA:
const apiPath = '/api';
const buildDir = path.join(__dirname, 'frontend', 'build');
// Serve static files like /index.html, /main.css and /main.js
app.use(express.static(buildDir));
// For every other path not under /api/*, serve /index.html
app.get(new RegExp('^(?!' + config.apiPath + '(/|$))'), function (req, res) {
res.sendFile(path.join(buildDir, 'index.html'));
});
// Setup some actions that don't need to be done for the static files like auth.
// The negative lookahead above allows those to be skipped.
// ...
// And now attach all the /api/* paths which were skipped above.
app.get(apiPath, function (req, res) { res.send('base'); });
app.get(apiPath, function (req, res) { res.send('users'); });
// And now a 404 catch all.
app.use(function (req, res, next) {
res.status(404).send('error: 404 Not Found ' + req.path)
})
// And now for any exception.
app.use(function(err, req, res, next) {
console.error(err.stack)
res.status(500).send('error: 500 Internal Server Error')
});
app.listen(3000)
Tested on [email protected], Node.js v14.17.0.