Search code examples
node.jsexpressmongooseexpress-router

Mongoose errors doesn't raise from router to app


There's single api application like this:

const express = require('express')
const app = express()
const router = require('express').Router()
...
route.post('/dogs', (req, res, next) => {
  const dog = new Dog() // it defined in real app
  dog.validate() // error happens here
    .then(() => {
      return res.status(201)
    })
    // [1]
})
...
app.use('/api/v1', router)
app.use(notFoundErrorHandler)
app.use(globalErrorHandler)

function notFoundErrorHandler (req, res, next) {
  res.status(404)
  res.send({error: 'Not found'})
}

function globalErrorHandler (err, req, res, next) {
  if (err) {
    res.status(err.status || 500)
    res.json({error: err.message || err})
  }
}

If there's validation error it won't pass to the globalErrorHandler, but catching and rethrowing error solves the problem [1]:

.catch(err => { return next(err) })

Does this behaviour is normal for mongoose with not complete Promise implimentation, or it could be implimentated in another way?

It doesn't raise error when using other methods like save, find, etc.


Solution

  • Thats normal, yes and has nothing to do with mongoose but with Express. Express doesn't handle unhanded exceptions implicit, you will have to handle them explicit. So in each route you will have to catch any errors and pass them to next.

    I know that this may be frustrating sometimes so I would suggest that you create a route manager of sorts that will register each route with an action handler and a try/catch pattern.

    There are many examples out there, here is one simple I like.

     var dogHandler = require('dogHandler')
    
     var serverRoutes = [{
         path: "dogs",
         method: "post",
         action: dogHandler
     }]
    
     serverRoutes.forEach(route => {
         app[route.method](route.path, (request, response, next) => {
             route.action(request, response)
                 .then(() => next)
                 .catch(err => next(err));
         });
     });