I know this question is being repeated again. I've already looked at other solutions and tried them already. I'd appreciate your help in debugging the issue.
I've a separate errorHandler
as a middleware.
error-handler.ts:
import express, { Request, Response, NextFunction } from "express";
export const errorHandler = (
err: Error,
req: express.Request,
res: express.Response,
next: express.NextFunction
) => {
console.log('Something went wrong');
res.status(400).send({
message: err.message
});
}
index.ts:
import express, { Request, Response, NextFunction } from 'express';
import { json } from 'body-parser';
import { currentUserRouter } from './routes/current-user';
import { signinRouter } from './routes/signin';
import { signoutRouter } from './routes/signout';
import { signupRouter } from './routes/singup';
import { errorHandler } from './middlewares/error-handlers';
const app = express();
app.use(json());
app.use(currentUserRouter);
app.use(signinRouter);
app.use(signoutRouter);
app.use(signupRouter);
app.use(errorHandler);
app.listen(3000, () => {
console.log('Listening on port 3000!!!');
})
When an Error
is thrown, the Express is not catching it.
signup.ts:
import express, { Request, Response } from "express";
const router = express.Router();
import { body, validationResult } from "express-validator";
const bodyValidation = [
body('email')
.isEmail()
.withMessage('Email must be valid'),
body('password')
.trim()
.isLength({ min: 4, max: 20})
.withMessage('Password must be between 4 and 20 characters')
];
router.post('/api/users/signup', bodyValidation, async (req: Request, res: Response) => {
const errors = validationResult(req);
if(!errors.isEmpty()) {
throw new Error('Invalid email or password');
}
console.log('Creating a user...');
res.send({});
});
export { router as signupRouter }
I can see Error: Invalid email or password
in the terminal being thrown. But Express is not catching the error being thrown.
CodePudding user response:
Express doesn't pay any attention to the return value of your route handler. You're passing an async
function to router.post
, which means that your function will return a promise to report its completion, rather than reporting it in the usual synchronous way. So any error thrown within the function is reported via the promise — which Express ignores.
In general, it's not a good idea to pass an async
function to something as a callback if that something (Express, in this case) doesn't support handling the Promise
the function returns.
In your example, you don't have any code using await
, so you could just remove the async
.
If you have code using await
that you left out to keep the question brief (which was perfectly reasonable), you might make that an inner function you call and use the promise from:
router.post("/api/users/signup", bodyValidation, (req: Request, res: Response) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
throw new Error("Invalid email or password");
}
console.log("Creating a user...");
(async () => {
// ...your code using `await` here...
// You're all done, send the result
res.send({});
})().catch((error) => {
// ...send error response...
});
});
Note how that code catches promise rejection in order to send an error response — you wouldn't want to just leave the promise rejection unhandled.
Another way you can do that is to ensure that the entire body of that inner function is in a try
/catch
:
router.post("/api/users/signup", bodyValidation, (req: Request, res: Response) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
throw new Error("Invalid email or password");
}
console.log("Creating a user...");
(async () => {
try {
// ...your code using `await` here...
// You're all done, send the result
res.send({});
} catch (error) {
// ...send error response...
}
})();
});