Reputation: 45
I'm using a router middleware to check if the request is valid or not. Also, I'm using a global Error handler middleware at the end of the server.js to catch and process all the errors.
Inside the router, I'm facing a problem implementing this. The following code will state the problem clearly.
Error middleware errorHandler.js
module.exports = function(err, req, res, next) {
//some logic
return res.status(400 or 500).json({err});
};
My server.js (short version)
const express = require('express');
const app = express();
app.use('/account/:accid/users', userRouteHandler);
const errorHandler = require('PATH to errorHandler.js file');
app.use(errorHandler);
app.listen(3000, () => console.log(`Example app listening on port 3000!`));
userRouteHandler file
var express = require('express');
var router = express.Router({ mergeParams: true });
router.use(express.json());
// middleware to use for all requests
router.use(function(req, res, next) {
/**** PROBLEM / CONFUSION ****/
checkIfAccountIdExists(req.params.accid) //if exists resolve(count) else reject(new Error)
.then(next) //I want to allow calling the get if it exists
.catch(next); //for error it should call the global error handler
});
router
.get('/', function(req,res,next){
console.log("entering here");
findAllTheUsers({accid:req.params.accid})
.then(users=>res.status(200).json(users);
.catch(err=>next(err)); //ensure it can call the global error handler
});
The code always calling the get route. As for both, I'm calling next(). If I call next() only inside then(), my global error handler will get skipped if any error occurs.
One way could be directly calling my errorHanler function within the catch block. but I want to keep my code separate and don't really want to require my errorHandler file within each route.
How can I achieve this?
Upvotes: 0
Views: 1268
Reputation: 858
Without knowing the behavior of your checkIfAccountIdExists
function, my supposition is that it returns a promise that always resolves with false|undefined|null
; something like this:
checkIfAccountIdExists(id).then((exists) => console.log(exists));
// outputs "false" or "undefined" or "null"
It's my supposition, because otherwise your .get('/')
route shouldn't even enter, given how next()
works.
next()
:Calling next()
(to the shame of Express) has always been confusing without having in-depth knowledge of it. It basically works in 3 ways:
next()
(no arguments) -> pass execution to next callbacks in the
routenext('route')
(the string 'route'
argument) -> bypass any remaining callbacks in the route (moves into any routes that follow)next(err)
(any other truthy parameters, aside from 'route'
) -> invokes the error handlers.In your specific case, my assumption is that checkIfAccountIdExists()
solves with false|undefined|null
, essentially invoking next(err)
signature, but because err
is not truthy, it's treated as a next()
signature, moving onto the next route callback. I'd check the sanity of checkIfAccountIdExists()
for this.
next()
with PromisesWhen using Promises, it's important to remember that your first argument of .then()
(meaning your fulfillment handler) will always receive a parameter!
promise.then(callback);
function callback() {
console.log(arguments.length); // ALWAYS 1
}
For this reason, you should always avoid setting next()
as a fulfillment handler to promises. Otherwise, once your checkIfAccountIdExists()
will solve with true
, it will actually invoke the next(err)
signature!
Always write: promise.then(() => next())
instead of promise.then(next)
, to make sure you call next
without arguments.
Writing promise.catch(next)
is however fine, because it's the same as promise.catch((err) => next(err))
Also, Promises (thenables
) allow for two arguments on .then()
, one being a fulfillment handler and one a rejection handler.
Example: promise.then(onFulfillment, onRejection)
which is similar to calling promise.then(onFulfillment).catch(onRejection)
except of how errors are caught!
.then(onFulfillment, onRejection)
any errors that are thrown
inside onFulfillment
are never caught by onRejection
..then(onFulfillment).catch(onRejection)
any errors that are thrown
inside onFulfillment
are also caught by onRejection
In your case, that means you can safely write
checkIfAccountIdExists.then(() => next(), next);
because the next route (onFulfillment arg) will also handle errors. Note: errors inside synchronous code will be caught by express.
More info:
Upvotes: 1