-1

I would like to validate params using these kind of middleware. The problem is that router.param is always applied before the first middleware router.all (I also tried with router.use, it doesn't work because the param is common to both middlewares). Is there a way to execute Middleware 1 before router.param ?

// Middleware 1
router.all('/:firstId/checklist/:**secondId**/*',
  (req, res, next) => {
     console.log('Request matched')
     next()
  },  
param('**secondId**', "Error message 2")
    .isMongoId(),
  checkValidationErrors
)

router.param('**secondId**', callback)

However, Middleware 1 does not work as I expected. If the param is a valid MongoDB ObjectId, 'Request matched' is logged, the next middlewares are applied accordingly depending on the request. If it is not a valid id, 'Request matched' is NOT logged, the expected error is NOT sent in the response. I get this error instead from Mongoose which comes from router.param :

MongooseError [CastError]: Cast to ObjectId failed for value "xxx" at path "_id" for model "XXX"                 

I tried to comment router.param and it solved the problem. So it is certainly related to the order of execution.

Thank you very much for your help

Abk
  • 376
  • 3
  • 10

2 Answers2

0

Flip this (The reason is in your case express is only looking for :firstId/* in both cases because it does fit for both scenarios. if the first pattern/path matches with the input URI, it does not go look for your middleware 2.

// Middleware 1
router.all('/:firstId/*',
  param('firstId', "Error message 1")
    .isMongoId(),
  checkValidationErrors        
)

// Middleware 2
router.all('/:firstId/checklist/:secondId/*',
  (req, res, next) => {
     console.log('Request matched')
     next()
  },  
param('secondId', "Error message 2")
    .isMongoId(),
  checkValidationErrors
)

To

// Middleware 2
router.all('/:firstId/checklist/:secondId/*',
  (req, res, next) => {
     console.log('Request matched')
     next()
  }, 

param('secondId', "Error message 2")
    .isMongoId(),
  checkValidationErrors
)

// Middleware 1
router.all('/:firstId/*',
  param('firstId', "Error message 1")
    .isMongoId(),
  checkValidationErrors        
)
JBone
  • 1,724
  • 3
  • 20
  • 32
  • Flipping doesn't work. checkValidationErrors uses next(), so both middleware are called if secondId is valid (I used several console.log() to be sure ), only the first middleware is called if secondId is not valid. – Abk Jan 22 '20 at 22:06
  • I updated the question, since the problem seems more related to the order of execution between the problematic middleware and another one using router.param. – Abk Jan 23 '20 at 10:47
0

I could not find a way to use a middleware with the same parameter as router.param and execute it before router.param, since router.param seems to be executed first systematically. But there is a workaround to be able to do this : regrouping middlewares which you want to execute before router.param in a separate file.

Instead of : app.js (main app file) routing to originalRouter (original router file).

The control flow should be : app.js (main app file) routing to beforeParamMiddlewwareRouter routing to originalRouter (original router file)

OR

In app.js :

app.use('/path', beforeParamMiddlewwareRouter, originalRouter)

Feel free to offer a better solution if you have one. I am open to suggestions.

Abk
  • 376
  • 3
  • 10