Catch all route EXCEPT for /login

node.jsExpress

node.js Problem Overview


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 /?

node.js Solutions


Solution 1 - node.js

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) {
  ...
});

Solution 2 - node.js

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();
  ...
});

Solution 3 - node.js

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.

Solution 4 - node.js

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)

Solution 5 - node.js

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionclifford.dukeView Question on Stackoverflow
Solution 1 - node.jsrobertklepView Answer on Stackoverflow
Solution 2 - node.jsLeonid BeschastnyView Answer on Stackoverflow
Solution 3 - node.jsSeday MatzumiyaView Answer on Stackoverflow
Solution 4 - node.jsJeremy MoritzView Answer on Stackoverflow
Solution 5 - node.jsCiro Santilli Путлер Капут 六四事View Answer on Stackoverflow