I’m developing a REST API with express that relies on a custom ApiError
class and a custom errorHandler
function for handling async errors in a scalable way.
As a refernce:
ApiError:
export class ApiError extends Error {
statusCode;
constructor(message: string, status = 500) {
super(message);
Error.captureStackTrace(this, this.constructor);
this.statusCode = status;
}
}
errorHandler:
type CustomError = Error | (new (...args: any[]) => Error);
export const errorHandler = (
err: CustomError,
req: Request,
res: Response,
next: NextFunction
) => {
console.log(`Error middleware: ${err}`);
if (err instanceof ApiError) {
return res.status(err.statusCode).json(err.message);
}
return res.status(500).json('Internal server error');
};
And at this point, in app.ts – after importing express-async-errors
– errorHandler
is used as the last middleware in order to handle all the ApiError
instances thrown by controllers:
app.ts:
/*
* Imports
*/
import 'express-async-errors';
/*
* Other middlewares and logic
*/
app.use('/api', router());
app.use(errorHandler);
The issue is that ts-node-dev
won’t handle ApiError
instances as such – this means that if at any point in the code there was an ApiError
thrown, the server would respond with the default handler provided in errorHandler
:
controller.ts:
/*
* After some logic
*/
throw new ApiError("This won't run", 400);
server response:
"Internal server error" //StatusCode: 500
In other words, the following condition would not evaluate to true:
if(new ApiError('...',400) instance of ApiError){
/*
* This won't run
*/
}
I can tell that the issue is related to ts-node-dev
and not the code itself as if I were to run the transpiled code inside dist
with nodemon
the server would respond as expected.