positron
positron

Reputation: 3693

Execute middleware on every route call

In my Express application I implement routes in routes.ts:

    var Router = express.Router();

    Router.route('/models/:modelId')
      .get(function (req, res) {
          service.setParameter(req)
          service.get(req,res)
    });
 
     Router.route('/models/:modelId')
      .post(function (req, res) {
          service.setParameter(req)
          service.post(req,res)
    });

And express.ts:

    export const App = express()

    App.use(express.json())
    App.use(express.urlencoded({ extended: true }))
    App.use(helmet())

    App.use('/', Router)

At each router call I'd like to execute a piece of code service.setParameter(req) that gets particular parameter from 'params', but I don't want to add to each router method explicitly.

I tried adding it at as middleware before and after Router

    App.use('/', Router)

    App.use(function(req, res, next){
      service.setParameter(req)
      next()
    })

But if I define it before Router then route hasn't been set yet, and I don't get the parameter I want, and if I define it after, then middleware is not executed.

How can execute service.setParameter(req) in a generic way so that it applies to all the routes?

Upvotes: 2

Views: 868

Answers (4)

positron
positron

Reputation: 3693

Thanks for all the answers, they helped me better understand how routing works on Express.

I found another solution, which I think works best in my case - using Router.all() method:

const setRequest = function(req, res, next){
  logger.setRequest(request)
  next()
}

Router.route('/models/:model_id')
.all(setRequest)
.get(function (req, res) {service.execute()})
.put(function (req, res) {service.execute()})

Upvotes: 0

NeNaD
NeNaD

Reputation: 20354

In express.ts file, you can add a middleware that would do it before mounding the Router, and then just procced forward with next(). You can do it like this:

App.use('/*', (req, res, next) => {
  service.setParameter(req);
  next();
});

App.use('/', Router)

Upvotes: 2

You can use app.use(async (req,res,next) => {...}) in order to declare a middleware that executes in all the requests, if you want this middleware to be called first, it must be declare before than your routes, the middleware have to call next() in order to continue with the execution flow, if you want to be called at the end of you request, you have to put at the end of your declarations but before of the error middleware, in that approach each route have to call next() at the end of your function.

First approach

const express = require('express');
const app = express();
const router = express.Router();
router.post('/', async (req, res) => {
    await service.post(req,res);
});

router.get('/', async (req, res) => {
    await service.get(req,res)
});

app.use((req,res,next) => {
   console.log("always called");
   next();
});
app.use('/',router);

Second approach

const express = require('express');
const app = express();
const router = express.Router();
router.post('/', async (req, res, next) => {
    await service.post(req,res);
    next();
});

router.get('/', async (req, res, next) => {
    await service.get(req,res);
    next();
});

app.use('/',router);
app.use((req,res) => {
   console.log("always called");
});

Upvotes: 0

eol
eol

Reputation: 24565

You need to place your custom middleware between the context path and your router inside app.use(..):

const router = express.Router();
router.post('/', (req, res) => {
    service.post(req,res);
});

router.get('/', (req, res) => {
    service.get(req,res)
});

app.use('/models', (req, res, next) => {
    service.setParameter(req);
    next();
}, router);

With above code the middleware will be excecuted for all requests to '/models'.

Upvotes: 0

Related Questions