Home > Blockchain >  Express: why middlewares doesn't work properly for independent routers?
Express: why middlewares doesn't work properly for independent routers?

Time:01-26

I have the following code with 3 independent routers

const Express = require("express")

const app = Express()

const usersRouter = Express.Router()
const productsRouter = Express.Router()
const storeRouter = Express.Router()

productsRouter.use((_, res, next) => {
  res.send("products fail")
  //next()
})

storeRouter.use((_, res, next) => {
  res.send("store fail")
  //next()
})

usersRouter.route("/users")
  .get((_, res) => res.send("users"))

productsRouter.route("/products")
  .get((_, res) => res.send("products"))

storeRouter.route("/store")
  .get((_, res) => res.send("store"))

app.use(usersRouter)
app.use(productsRouter)
app.use(storeRouter)

app.listen(80, () => console.log("running"))

But every time I request /store route it pass through productRouter middleware which is assigned only to it.

I can't understand this behavior.

Why is this? How can I manage independent middlewares for each one?

GET /store 200
products fail

Expected

GET /store 200
store fail

CodePudding user response:

When you do this:

app.use(productsRouter)

that sends ALL requests to the productsRouter and thus its middleware runs for all requests. So, when you have this:

productsRouter.use((_, res, next) => {
  res.send("products fail")
  //next()
});

That will run on every single request.

If you want the router to only see certain requests, then register the router on a path instead so the router only gets requests destined for a certain path.

app.use("/products", productsRouter)

And, then remove the path itself from the router's routes since the path will have already been filtered.

CodePudding user response:

In order to achieve the expected behavior, you will have to make little changes to your code.

First: Take this approach, since it will allow you to keep everything clean and separated (this is crucial if you want to implement specific middlewares for each route).

usersRouter.
  .get("/", (req, res) => res.send("users"))

productsRouter.route
  .get("/", (req, res) => res.send("products"))

storeRouter.route("/store")
  .get("/", (req, res) => res.send("store"))

app.use("/users", usersRouter)
app.use("/products", productsRouter)
app.use("/store", storeRouter)

Instead of this one

usersRouter.route("/users")
  .get((_, res) => res.send("users"))

productsRouter.route("/products")
  .get((_, res) => res.send("products"))

storeRouter.route("/store")
  .get((_, res) => res.send("store"))

app.use(usersRouter)
app.use(productsRouter)
app.use(storeRouter)

Second: Uncomment the next() call on your middlewares, identify the request parameter on their callbacks and store them in variables (not crucial, but improves readability)

const productsMiddleware = (req, res, next) => {
  res.send("products fail")
  next()
}

const storeMiddleware = (res, res, next) => {
  res.send("store fail")
  next()
}

Third: Pass the middleware you want to apply to a specific controller right after the route and before the actual controller declaration on your router. E.G.

usersRouter.
  .get("/", (req, res) => res.send("users"))

productsRouter.route
  .get("/", productsMiddleware, (req, res) => res.send("products"))

storeRouter.route("/store")
  .get("/", storeMiddleware, (req, res) => res.send("store"))

By doing all this things, you'll end up with "independent middlewares" that only apply to the specified route/controller.

  •  Tags:  
  • Related