sdgfsdh
sdgfsdh

Reputation: 37121

Express middleware confusion

I have an app like this:

import express from 'express';

const middleware = tag => (req, res, next) => {
  console.log('middleware ' + tag);
  next();
};

const app = express();

const router = express.Router();

router.use(middleware('a'));

router.get('/x', (req, res) => res.json({ message: 'x' }));

app.use(router);

app.use(middleware('b'));

app.get('/y', (req, res) => res.json({ message: 'y' }));

app.use(middleware('c'));

app.listen(3000);

However, Router does not behave as I expected:

$ curl localhost:3000/x

middleware a

$ curl localhost:3000/y

middleware a

middleware b

Why does hitting /y call the middleware? I thought that the middleware was only applied to router.

How can I apply a middleware to only router, and not the other routes in app?

Upvotes: 2

Views: 142

Answers (2)

Sergey Lapin
Sergey Lapin

Reputation: 2693

When you do

app.use(router);

you mount the router at the root / path of your app. The router's middleware

router.use(middleware('a'));

is mounted at the root path or the router, and so at the root path of the app. Middleware mounted at the root path is executed for every request.

How can I apply a middleware to only router, and not the other routes in app?

You can mount the router at /x and make the router handle / its root path:

router.get('/', (req, res) => res.json({ message: 'x' }));
app.use('/x', router);

Upvotes: 1

Elliot Blackburn
Elliot Blackburn

Reputation: 4174

Even if you've done it via a router, because you then attached the router with no sub-path it bundled everything together. In your example you have attached everything to the same parent endpoint /, so even though it's done via a router you are then attaching this router to the / path.

If you want to just separate middleware out as you've indicated then you have two options.

  1. Sub-path the endpoints to something like /feature1/x and /feature2/y. Attach the middleware to the /feature1 and /feature2 respectively. This will give you the desired outcome. This could be done by attaching your router for endpoint /x in this way:

    app.use('/feature1', router);

Which would mean you now have the endpoints /feature1/x and /y. Each triggering it's independent chain of middleware.

  1. Attach the middleware to the specific endpoint such as:

    app.get('/x, middleware('a'), (req, res) => res.json({message: 'x'});
    app.get('/y', middleware('b'), (req, res) => res.json({message: 'y'});
    

What you've done at the moment is attach everything to the same route path (in this case the top level slash /).

Upvotes: 2

Related Questions