I'm using Express and I want to use the build-in middlewares to handle errors.
I'm using it this way -
app.use((err,req,res,next)=> {
console.log('error');
)};
Now this middleware is reached only if I'm using next(error) (where error is object of type Error) in my router.
On the other hand, if I simply throw new Error() in my router, the middleware is not called.
Is there any way to omit the next()?
So that if any error is thrown in my router, it will be handled by the middleware?
If you can use Node.js >= 8 that comes with async/await then you can use the following wrapper function over your routes:
const wrap = fn => {
return async function(req, res, next) {
let e = null;
try {
await fn(req, res, next);
} catch (err) {
e = err;
next(err);
}
if (!e) {
next();
}
};
};
app.get(
"/path",
wrap(async (req, res) => {
// use sync style code here which can throw
})
);
If the throw is synchronous, you could invent your own request handler wrapper that would catch any exceptions and turn them into a call to next():
app.get2 = function(path, fn) {
app.get(path, function(req, res, next) {
try {
fn(req, res, next);
} catch(err) {
next(err);
}
});
};
And, sample usage:
app.get2("/test", function(req, res, next) {
throw new Error("testing..."); // will end up in next()
});
Then, if your fn function throws synchronously, then it will be caught by your get2() wrapper and will automatically call next(err) for you.
If you're throwing asynchronously, this won't work. There is no generic wrapper for asynchronous throws because throws into an asynchronous callback don't throw to your code - they throw back into the asynchronous infrastructure for whatever async operation you were using and only they can catch it. If you use promises exclusively for your asynchronous operations, then the promise infrastructure will automatically catch your throws and turn them into rejected promises and you could do something similar to above for a returned and rejected promise. The Koa framework (a derivative of Express) does something similar already and I think Express 5 will have some features like that to.
Related
I have an express backend application. The problem I have is that all the routes contains the same try-catch piece which causes code bloat in my program:
// routes.js
router.get('/', async (req, res, next) => {
try {
const data = extractData(req)
await foo(data)
} catch (err) {
next(err)
}
})
// controllers.js
async function foo(data) {...do smh}
As you see above, try { extractData() } catch (err) { next(err) } portion of the code exists in all of the routes defined in the app.
I tried to create a wrapper function that takes controller function as parameter and use it as:
// routes.js
router.get('/', controllerWrapper(req, res, next, foo))
// controller-wrapper.js
async function controllerWrapper(req, res, next, controllerFunc) {
try {
const data = extractData(req)
await controllerFunc(data)
} catch (err) {
next(err)
}
}
But this does not work due to function being invoked, and not being actually a callback.
How can I achieve this?
You should use a closure for this, so you can return the middleware function from controllerWrapper and use the controllerFunc inside the returned middleware
function controllerWrapper(controllerFunc) {
return async function (req, res, next) {
try {
const data = extractData(req)
await controllerFunc(data)
} catch (err) {
next(err)
}
}
}
router.get('/', controllerWrapper(foo))
I have a problem and I haven't found a solution yet. I want to catch all errors if occur any error in each route but it's very inconvenient when I have to do it many times.
How can i implement it as a middleware same like app.use(ErrorHandle); ?
Code in ErrorHandler.js:
export const ErrorHandler = func => async (req, res, next) => {
try {
await func(req, res, next);
} catch (error) {
next(error);
}
}
Code in index.js
app.use((err, req, res, next) => {
if (err) {
return res.status(err.statusCode || 500).json(err.message);
}
next()
});
Code in route need to catch error:
import { ErrorHandler } from './ErrorHandler';
export const uploadMedia = ErrorHandler(async (req, res) => {
// do something...
let error = new Error();
error.statusCode = 404;
error.message = 'Content not found!';
}
Sorry if misunderstood your question... When you do the code below which you provided, you are assuming that if an error reaches the end of the stack via next(err), such handler should be called. Hence it's the last declaration after all your routes.
app.use((err, req, res, next) => {
if (err) {
return res.status(err.statusCode || 500).json(err.message);
}
next()
});
That, however, won't catch unhandledExceptionErrors. You still need the good old
try {
// throw error somewhere
} catch (e) {
next(e);
}
Personally, I haven't tried this package but it seems so be a nice hack for Express router's inability to handle promise returns. About express-promise-router:
A simple wrapper for Express 4's Router that allows middleware to return promises. This package makes it simpler to write route handlers for Express when dealing with promises by reducing duplicate code.
How can I achieve this. In an easy way in ExpressJS?
App.get("/", async (req, res, next) => {
await something.catch(err => {
res.status(500).json("something wrong")
})
if (res.headersSent) return;
res.json("2st response");
});
Can I just call res.json() two time then express automatically understand to end response and not to send second response ? without of using middleware to check that response already send or not!
In your logic here with await, it's easier to just use try/catch instead of .catch() and that makes the flow a lot easier:
App.get("/", async (req, res, next) => {
try {
await something;
} catch(err) {
res.status(500).json("something wrong");
return;
});
res.json("2st response");
});
In general, you don't mix await with .catch() and partly for this reason because using await and try/catch makes code flow like this simpler since you directly return from the outer function in the try/catch(err) statement, but you cannot do that in the .catch() statement.
You can use return before res.send. This way it will send a response and exit the function.
app.get("/", (req, res, next) => {
return res.send("1st responce");
// Unreachable code
if(res.headersSent) return;
res.json("2st responce")
})
Here is the problem that I am facing in express.
Somewhere in my express middleware, I want to check for the presence of a file.
//Setting up express middeleware...
app.use(f1);
app.use(f2);
...
function f1(req, res, next) {
...
//Here I want to check if 'somefile' exists...
fs.access('somefile', callback1, req, res, next);
}
//In the callback, I want to continue with the middleware...
function callback1(err, req, res, next) {
if (err) {
//Report error but continue to next middleware function - f2
return next();
}
//If no error, also continue to the next middleware function - f2
return next();
}
function f2(req, res, next) {
}
How do I pass req, res, next as arguments to the callback of fs.access?
The above code does not work. I suspect I need to use closures but how?
A totally different way of looking at the problem is: How do I use, for example, fs.access, itself as a express middleware function?
For me this approach have much more sense:
Assume you want to create a middleware in f1, and then have a middleware for error handling handleError, and any other middleware.
For f1 you already have the req, res in the closure so you will have access in fs.access callback.
function f1(req, res, next) {
fs.access('somefile', (err) => {
if (err) return next(err);
// here you already have access to req, res
return next();
}
}
function f2(req, res, next) {
// do some stuff if there is err next(err);
}
function handleError(err, req, res, next) {
if (err) {
// handle somehow the error or pass down to next(err);
}
}
app.use(f1); // you pass down the err |
app.use(f2); // ------------ |
app.use(handleError); // <----|
Can someone expound on the times when it's appropriate in a node.js Express app to throw an error like so:
throw new Error('my error');
or to pass this error on via the callback usually labelled 'next' like so:
next(error);
and could you please explain what each of them will do in the context of an Express app?
for example, here is an express function dealing with URL parameters:
app.param('lineup_id', function (req, res, next, lineup_id) {
// typically we might sanity check that user_id is of the right format
if (lineup_id == null) {
console.log('null lineup_id');
req.lineup = null;
return next(new Error("lineup_id is null"));
}
var user_id = app.getMainUser()._id;
var Lineup = app.mongooseModels.LineupModel.getNewLineup(app.system_db(), user_id);
Lineup.findById(lineup_id, function (err, lineup) {
if (err) {
return next(err);
}
if (!lineup) {
console.log('no lineup matched');
return next(new Error("no lineup matched"));
}
req.lineup = lineup;
return next();
});
});
In the line commented "//should I create my own error here?"
I could used "throw new Error('xyz')", but what exactly would that do? Why is it usually better to pass the error to the callback 'next'?
Another question is - how do I get "throw new Error('xyz')" to show up in the console as well as the browser when I am in development?
In general express follows the way of passing errors rather than throwing it, for any errors in the program you can pass the error object to 'next', also an error handler needs to be defined so that all the errors passed to 'next' can be handled properly.
http://expressjs.com/en/guide/error-handling.html
Throwing an error inside a callback doesn't work:
app.get('/', function (req, res) {
fs.mkdir('.', (err) => {
if (err) throw err;
});
});
But calling next works:
app.get('/', function (req, res, next) {
fs.mkdir('.', (err) => {
if (err) next(err);
});
});
Errors that occur in synchronous code inside route handlers and middleware require no extra work. If synchronous code throws an error, then Express will catch and process it. For example:
app.get('/', function (req, res) {
throw new Error('BROKEN') // Express will catch this on its own.
})
For those who prefer throwing errors, here is a workaround decorator:
export function safeThrow(
target: object,
key: string | symbol,
descriptor: TypedPropertyDescriptor<(req: Request, res: Response, next: NextFunction) => Promise<any>>) {
const fun = descriptor.value;
descriptor.value = async function () {
try {
await fun.apply(this, arguments);
} catch (err) {
arguments[2](err);
}
};
}
#safeThrow
private async get(req: Request, res: Response, next: NextFunction) {
throw { status: 404, message: 'Not supported' }
}