I am developing a backend with a database in mongoDB, when defining an endpoint of type post and testing it in postman it sends me an error in the console and in postman I do not get the object that I defined as a response to the post, however if it performs the incersion correctly in the database
this is the route
/*
/api/hospitales
*/
const { Router } = require('express');
const { check } = require('express-validator');
const {
getHospitales,
crearHospital,
actualizarHospital,
eliminarHospital
} = require('../controller/hospitales_controller');
const { validarCampos } = require('../middlewares/validarCampos_middleware');
const { validarJWT } = require('../middlewares/validarJWT_middleware');
const router = Router();
router.get('/', [], getHospitales);
router.post('/', [
validarJWT,
check('nombre', 'El nombre del hospital es necesario').not().isEmpty(),
validarCampos
], crearHospital);
router.put('/:id', [], actualizarHospital);
router.delete('/:id', [], eliminarHospital);
module.exports = router;
this is the controller
const { response } = require('express');
const Hospital = require('../model/hospitales_model');
const crearHospital = async(req, res = response) => {
const uid = req.uid;
const hospital = new Hospital({
usuario: uid,
...req.body
});
try {
const hospitalDB = await hospital.save();
res.json({
ok: true,
hospital: hospitalDB
});
} catch (error) {
console.log(error);
res.status(500).json({
ok: false,
msg: 'Hable con el administrador'
});
}
};
This is the model
const { Schema, model } = require('mongoose');
const HospitalSchema = Schema({
nombre: {
type: String,
required: true
},
img: {
type: String,
},
usuario: {
required: true,
type: Schema.Types.ObjectId,
ref: 'Usuario'
}
}, { collection: 'Hospitales' });
HospitalSchema.method('toJSON', function() {
const { __v, ...object } = this.toObject();
return object;
});
module.exports = model('Hospital', HospitalSchema);
this is the error in console
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:536:11)
at ServerResponse.header (Z:\NODE\N_BackEndAdminPro\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (Z:\NODE\N_BackEndAdminPro\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (Z:\NODE\N_BackEndAdminPro\node_modules\express\lib\response.js:267:15)
at crearHospital (Z:\NODE\N_BackEndAdminPro\controller\hospitales_controller.js:24:13)
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
(node:14752) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:536:11)
at ServerResponse.header (Z:\NODE\N_BackEndAdminPro\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (Z:\NODE\N_BackEndAdminPro\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (Z:\NODE\N_BackEndAdminPro\node_modules\express\lib\response.js:267:15)
at crearHospital (Z:\NODE\N_BackEndAdminPro\controller\hospitales_controller.js:31:32)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:14752) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:14752) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
this is the result in postman
Solved, Like many of the code problems that exist it was simply an extra call of the next() function in the validateJWT middleware that accompanies the request
bad code
const jwt = require('jsonwebtoken');
const validarJWT = (req, res, next) => {
//leer token
const token = req.header('x-token');
if (!token) {
return res.status(401).json({
ok: false,
msg: 'No hay token en la peticion'
});
}
try {
const { uid } = jwt.verify(token, process.env.JWT_SECRET);
req.uid = uid;
next();
} catch (error) {
return res.status(401).json({
ok: false,
msg: 'Token invalido'
});
}
next();
};
rigth code
const jwt = require('jsonwebtoken');
const validarJWT = (req, res, next) => {
//leer token
const token = req.header('x-token');
if (!token) {
return res.status(401).json({
ok: false,
msg: 'No hay token en la peticion'
});
}
try {
const { uid } = jwt.verify(token, process.env.JWT_SECRET);
req.uid = uid;
} catch (error) {
return res.status(401).json({
ok: false,
msg: 'Token invalido'
});
}
next();
};
Related
I am trying to use the Get method from the code below. I can use the Post method to post new instances to the database but my Get method is not working. When I tried to use the Get method I encountered the "AxiosError: Request failed with status code 404" error.
This is my code that contains the Get and Post methods:
const express = require('express');
const mongoose = require('mongoose');
const { ObjectId } = require('mongodb');
const { connectToDb, getDb, URI } = require('./db');
const Root = require('../models/Root');
const port = process.env.PORT || 7000;
const URL = 'http://localhost:7000'
const axios = require('axios');
// init & middleware
const app = express();
const router = express.Router();
app.use(express.json());
mongoose.set('strictQuery', false);
mongoose.set('bufferCommands', false);
let db
connectToDb((err) => {
if (!err) {
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
}
});
mongoose.connect(URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
// POST
app.post('/roots', async (req, res) => {
const { root_id, node_id, name } = req.body;
if (!root_id || !node_id || !name) {
return res
.status(400).send({ error: 'Please provide all required fields' });
}
const root = new Root({ root_id, node_id, name });
try {
const savedRoot = await root.save();
res.send(root);
} catch (err) {
//console.error('Error saving root:', err);
res.status(400).send(err);
}
});
// GET
app.get('/roots/:root_id', async (req, res) => {
try {
const response = await axios.get(
`${URL}/roots?filter={"where":{"root_id":${req.params.root_id}}}`
);
res.status(200).json(response.data);
} catch (err) {
console.error('Error getting root:', err);
res.status(400).send(err);
// res.status(500).json({ error: 'Could not fetch the root' });
}
});
// DELETE
app.delete('/roots/:root_id', async (req, res) => {
try {
await axios.delete(`${URL}/roots/${req.params.root_id}`);
res.status(200).json({ message: 'Root deleted successfully' });
} catch (err) {
console.error('Error getting root:', err);
res.status(400).send(err);
// res.status(500).json({ error: 'Could not delete the root' });
}
// Call to a method to delete all children nodes of the tree in the Node tables
});
// PATCH
app.patch('/roots/:root_id', async (req, res) => {
try {
const response = await axios.patch(
`${URL}/roots/${req.params.root_id}`,
req.body
);
res.status(200).json(response.data);
} catch (err) {
res.status(500).json({ error: 'Could not update the root' });
}
});
I use this code to connect to the database:
// Use this file to connect to database - easy to switch between local and cloud for testing
const{MongoClient} = require('mongodb')
let dbConnection
// Connect to local database
let URI = 'mongodb://127.0.0.1:27017/PM_AI'
module.exports = {
connectToDb: (cb) => {
MongoClient.connect(URI)
// MongoClient.connect(cloudURI)
.then((client) => {
dbConnection = client.db()
return cb()
})
.catch(err => {
console.log(err)
return cb(err)
})
},
getDb: () => dbConnection,
URI
}
ERROR LOG for the error that I encounter:
{
"message": "Request failed with status code 404",
"name": "AxiosError",
"stack": "AxiosError: Request failed with status code 404\n at settle (D:\\CSDS_395_Project\\AI-PM\\node_modules\\axios\\dist\\node\\axios.cjs:1900:12)\n at IncomingMessage.handleStreamEnd (D:\\CSDS_395_Project\\AI-PM\\node_modules\\axios\\dist\\node\\axios.cjs:2944:11)\n at IncomingMessage.emit (node:events:525:35)\n at endReadableNT (node:internal/streams/readable:1359:12)\n at process.processTicksAndRejections (node:internal/process/task_queues:82:21)",
"config": {
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
},
"adapter": [
"xhr",
"http"
],
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1,
"env": {},
"headers": {
"Accept": "application/json, text/plain, */*",
"User-Agent": "axios/1.3.3",
"Accept-Encoding": "gzip, compress, deflate, br"
},
"method": "get",
"url": "http://localhost:7000/roots?filter={\"where\":{\"root_id\":1}}"
},
"code": "ERR_BAD_REQUEST",
"status": 404
}
The URL that I use to test my method in Postman is http://localhost:7000/roots/1.
Please let me know what am I doing wrong with my code here.
Thank you very much!
In your expressjs server file, the url you are using in mongoose.connect() refers to the expressjs server itself instead of localhost mongodb instance
So in your server.js/app.js or whatever is your main expressjs server file,
const MONGO_URL = 'mongodb://127.0.0.1:27017/PM_AI'
I can also see that you are using both mongo client and mongoose which I don't understand why... You only need one of these libaries to connect to mongodb from your backend
Also your code is pretty messed up so I've made the following changes
No need to use mongoose strict query and other configurations, simply using mongoose.connect() in latest mongoose version is enough. As mongodb connection establishes, you can launch your server
In terminal, write npm install dotenv. It is a package that is used to access variables in .env file, without it your server won't work properly
I've removed mongo client as it is not needed, simply using mongoose is enough
I don't know why you are making axios requests to your own server. This axios thing is what is causing 404 error. You should use axios only when you need to make api calls from frontend, or make api calls from your backend to some other backend server. For your own server, you should always prefer using a controller function for every route otherwise you will get 404 error. By controller function, I mean instead of axios.get, you need to execute mongoModel.delete() instead of axios.delete() or return mongoModel.findById() instead of axios.get()
For mongodb connection, use MONGO_URL and for connecting your own server, use URL
So the final version of your code should look like:
const express = require('express');
const mongoose = require('mongoose');
const { ObjectId } = require('mongodb');
const Root = require('../models/Root');
const MONGO_URL = 'mongodb://127.0.0.1:27017/PM_AI'
const axios = require('axios');
// For environmental variables in .env file
const dotenv = require("dotenv")
dotenv.config()
// init & middleware
const app = express();
const router = express.Router();
app.use(express.json());
const port = process.env.PORT || 7000
const URL = `http://localhost:${port}`
mongoose.connect(MONGO_URL).then(() => {
console.log("Mongodb connected")
app.listen(port,() =>
{console.log("Server started") }
});
// POST
app.post('/roots', async (req, res) => {
const { root_id, node_id, name } = req.body;
if (!root_id || !node_id || !name) {
return res
.status(400).send({ error: 'Please provide all required fields' });
}
const root = new Root({ root_id, node_id, name });
try {
const savedRoot = await root.save();
res.send(root);
} catch (err) {
//console.error('Error saving root:', err);
res.status(400).send(err);
}
});
// GET
app.get('/roots/:root_id', async (req, res) => {
try {
const response = await axios.get(
`${URL}/roots?filter={"where":{"root_id":${req.params.root_id}}}`
);
res.status(200).json(response.data);
} catch (err) {
console.error('Error getting root:', err);
res.status(400).send(err);
// res.status(500).json({ error: 'Could not fetch the root' });
}
});
// DELETE
app.delete('/roots/:root_id', async (req, res) => {
try {
await axios.delete(`${URL}/roots/${req.params.root_id}`);
res.status(200).json({ message: 'Root deleted successfully' });
} catch (err) {
console.error('Error getting root:', err);
res.status(400).send(err);
// res.status(500).json({ error: 'Could not delete the root' });
}
// Call to a method to delete all children nodes of the tree in the Node tables
});
// PATCH
app.patch('/roots/:root_id', async (req, res) => {
try {
const response = await axios.patch(
`${URL}/roots/${req.params.root_id}`,
req.body
);
res.status(200).json(response.data);
} catch (err) {
res.status(500).json({ error: 'Could not update the root' });
}
});
I have the following route setup in my node js api app:
const { body } = require("express-validator");
router.post(
"/user/signup",
[
body("firstName").not().isEmpty().withMessage("First name is required"),
body("lastName").not().isEmpty().withMessage("Last name is required"),
body("email")
.isEmail()
.withMessage("Email is required")
.custom((value, { req }) => {
return User.findOne({ email: value }).then(userDoc => {
if (userDoc) {
return Promise.reject('E-Mail address already exists!');
}
});
}),
body("mobile").not().isEmpty().withMessage("Mobile is required"),
body("password").not().isEmpty().withMessage("Password is required"),
body("confirmPassword")
.not()
.isEmpty()
.withMessage("Confirm password is required"),
],
UserController.signup
);
signup method in UserController
const { validationResult } = require("express-validator");
exports.signup = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error('Validation failed.');
error.statusCode = 422;
error.data = errors.array();
throw error;
}
const {
firstName,
lastName,
email,
mobile,
password,
confirmPassword
} = req.body;
try {
if (password !== confirmPassword) {
res
.status(422)
.json({ message: "Password and confirm password must be same" });
}
//save user and return response to front end
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};
Code block at the end of app.js to catch error:
/** Catch and return custom errors */
app.use((error, req, res, next) => {
const status = error.statusCode || 500;
const message = error.message;
const data = error.data;
res.status(status).json({ message: message, data: data });
});
In this route I'm checking if user has already registered with same email or not. If user has been registered with same email return error message.
Error message returned by server before crash:
/storage/node/Jeevan-Api/controllers/UserController.js:10
const error = new Error('Validation failed.'); ^
Error: Validation failed.
at exports.signup (/storage/node/Jeevan-Api/controllers/UserController.js:10:19)
at Layer.handle [as handle_request] (/storage/node/Jeevan-Api/node_modules/express/lib/router/layer.js:95:5)
at next (/storage/node/Jeevan-Api/node_modules/express/lib/router/route.js:144:13)
at middleware (/storage/node/Jeevan-Api/node_modules/express-validator/src/middlewares/check.js:16:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
statusCode: 422,
data: [
{
value: 'user#user.com',
msg: 'E-Mail address already exists!',
param: 'email',
location: 'body'
}
]
}
[nodemon] app crashed - waiting for file changes before starting...
The above code does the job but the server crashes after it returns the error message. This is happening in both local server and my development server.
How can I return validation message and
You are throwing error which makes the app to stop processing to the next request or response / middleware. What you could do is doing next(error) so it will catch in the last catch block.
Or you could also look into this to set up error handling in express; https://expressjs.com/en/guide/error-handling.html#:~:text=Writing%20error%20handlers
This is happening because your middleware is throwing an async error and your node app has no way of handling it.
Even if you have an error handler in place you need to explicitly call the next function with the error object.
E.g.
try{
// Your code...
}catch(error){
console.log(error)
next(error)
}
When express sees next(error) i.e. next function being called with an argument it passes it to the error handler that you have written at the end of app.js
/** Catch and return custom errors */
app.use((error, req, res, next) => {
const status = error.statusCode || 500;
const message = error.message;
const data = error.data;
res.status(status).json({ message: message, data: data });
});
Solution:
You can make use of an npm package express-async-errors
Link for the npm package: https://www.npmjs.com/package/express-async-errors
And in your app.js file just add require('express-async-errors') on the very top. This will direct all the async errors to the error handler middleware in your application.
Here are the screenshots and code attached
Code:
exports.forgotPassword = async function(req, res, next) {
//Check if user exists
const user = await User.findOne({ email: req.body.email })
if (!user) {
return next(new AppError('There is no user with this email address', 404))
}
//Generate the random reset token
const resetToken = user.createPasswordResetToken()
await user.save({ validateBeforeSave: false });
//send it to user's mail
const resetURL = `${req.protocol}://${req.get('host')}/api/users/resetPassword/${resetToken}`;
const message = `Forgot your Password? Submit a patch request with your password and confirm password to ${resetURL}`
try {
await sendEmail({
email: user.email,
subject: 'Your password reset token(valid for 10 min)'
})
res.status(200).json({
status: 'success',
message: 'Token sent to Email'
})
} catch (err) {
user.passwordResetToken = undefined;
user.passwordResetExpires = undefined;
await user.save({ validateBeforeSave: false });
return next(new AppError('There was an error sending the email. Please try again later!'), 500);
}
}
Error Message :
Error: There was an error sending the email. Please try again later!
at exports.forgotPassword (D:\FYP\controllers\authController.js:94:22)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Error: getaddrinfo ENOTFOUND smtp.mailtrap.io;
at GetAddrInfoReqWrap.onlookup [as oncomplete]
(node:dns:71:26) {
errno: -3008,
code: 'EDNS',
syscall: 'getaddrinfo',
hostname: 'smtp.mailtrap.io;',
command: 'CONN'
}
look at my code
it used express.js with typescript
use ndoemailer to send email
https://nodemailer.com/about/
public async forgot(entity: AuthEntity): Promise<void> {
if (isEmpty(entity)) throw new HttpException(StatusCodes.BAD_REQUEST, i18n.t("api.commons.reject"));
let findUser: IUser;
if (entity.email !== undefined) {
findUser = await this.userModel.findOne({ email: entity.email });
if (!findUser) {
// #ts-ignore
await ipActivityModel.storeIp(false, "forgot", entity);
throw new HttpException(StatusCodes.CONFLICT, i18n.t("auth.youAreNotEmail"));
}
await this.sendForgotEmail(findUser.email, entity.resetToken);
}
}
public async sendForgotEmail(email: string, hash: string): Promise<void> {
const transporter = nodemailer.createTransport({
host: config.get("email.host"),
port: config.get("email.port"),
secure: config.get("email.secure"), // true for 465, false for other ports
auth: config.get("email.auth")
});
const mailContext = {
siteAddress: config.get("siteAddress"),
emailForgotTitle: i18n.t("auth.emailForgotTitle"),
emailForgotGuide: i18n.t("auth.emailForgotGuide"),
emailActivateHash: i18n.t("auth.emailActivateHash"),
hash: hash,
emailForgotVisit: i18n.t("auth.emailForgotVisit"),
emailActivateIgnore: i18n.t("auth.emailActivateIgnore"),
emailForgotResetFrom: i18n.t("auth.emailForgotResetFrom")
};
const template = await ejs.renderFile("./dist/modules/auth/views/forgot.html", mailContext);
const mailOptions = {
from: config.get("email.fromEmail"),
to: email,
subject: config.get("siteAddress") + " (" + i18n.t("api.events.emailForgot") + ")",
html: template
};
let isSend = await transporter.sendMail(mailOptions);
if (!isSend.messageId) {
throw new HttpException(StatusCodes.CONFLICT, i18n.t("auth.emailSendErrorForgot"));
}
}
I am getting this error ->
(node:18420) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'name' of undefined
at C:\Users\ohrid\Desktop\backend2\routes\categories.js:27:24
at Layer.handle [as handle_request] (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:281:22
at Function.process_params (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:275:10)
at Function.handle (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:174:3)
at router (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:47:12)
at Layer.handle [as handle_request] (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:317:13)
at C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\ohrid\Desktop\backend2\node_modules\express\lib\router\index.js:275:10)
at logger (C:\Users\ohrid\Desktop\backend2\node_modules\morgan\index.js:144:5)
(node:18420) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:18420) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
My routes/categories.js:
const { Category } = require('../models/category')
const express = require('express')
const router = express.Router()
router.get(`/`, async (req, res) => {
const categoryList = await Category.find()
if (!categoryList) {
res.status(500).json({ success: false })
}
res.status(200).send(categoryList)
})
router.get('/:id', async (req, res) => {
const category = await Category.findById(req.params.id)
if (!category) {
res.status(500).json({
message: 'The category with the given ID was not found.',
})
}
res.status(200).send(category)
})
router.post('/', async (req, res) => {
let category = new Category({
name: req.body.name,
icon: req.body.icon,
color: req.body.color,
})
category = await category.save()
if (!category)
return res.status(400).send('the category cannot be created!')
res.send(category)
})
router.put('/:id', async (req, res) => {
const category = await Category.findByIdAndUpdate(
req.params.id,
{
name: req.body.name,
icon: req.body.icon || category.icon,
color: req.body.color,
},
{ new: true }
)
if (!category)
return res.status(400).send('the category cannot be created!')
res.send(category)
})
router.delete('/:id', (req, res) => {
Category.findByIdAndRemove(req.params.id)
.then((category) => {
if (category) {
return res
.status(200)
.json({
success: true,
message: 'the category is deleted!',
})
} else {
return res
.status(404)
.json({ success: false, message: 'category not found!' })
}
})
.catch((err) => {
return res.status(500).json({ success: false, error: err })
})
})
module.exports = router
My app.js
const express = require('express')
const app = express()
const morgan = require('morgan')
const mongoose = require('mongoose')
const cors = require('cors')
const dotenv = require('dotenv')
require('dotenv/config')
app.use(cors())
app.options('*', cors())
//middleware
app.use(morgan('tiny'))
//Routes
const categoriesRoutes = require('./routes/categories')
const productsRoutes = require('./routes/products')
const usersRoutes = require('./routes/users')
const ordersRoutes = require('./routes/orders')
const api = process.env.API_URL
app.use(`${api}/categories`, categoriesRoutes)
app.use(`${api}/products`, productsRoutes)
app.use(`${api}/users`, usersRoutes)
app.use(`${api}/orders`, ordersRoutes)
mongoose
.connect(
'mongodb+srv://dani:Luka5678#cluster0.23wee.mongodb.net/e-shop?retryWrites=true&w=majority',
{
useNewUrlParser: true,
useUnifiedTopology: true,
dbName: 'e-shop',
}
)
.then(() => {
console.log('Database connection is ready')
})
.catch((err) => {
console.log(err)
})
app.listen(4000, () => {
console.log('server is running on http://localhost:4000')
})
What should I change?
You don't have any error handling layer in your application.
If you use Express v5 and above, route handlers and middleware that return a Promise will catch the errors and will call next(value) automatically.
Otherwise, from asynchronous functions, you must pass them to the next() function, where Express will catch and process them.
That way, you won't get the UnhandledPromiseRejectionWarning.
I have a form and I am trying to validate it with express-validator. When there are no validation errors, I get no error in the console, but when there are validation errors I try to pass them to my EJS template, but it gives me an error in the console. This is my full code:
var express = require('express');
var app = express();
var path = require('path');
var mongoose = require('mongoose');
var bodyParser = require('body-parser')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))
const { check, validationResult } = require('express-validator');
app.listen(8080);
// saytin asuma inch template piti ogtagorcvi
app.set('view engine', 'ejs');
// MongoDB
let dbUrl = 'mongodb+srv://grig:xxxXXXxxx#cluster0-osvfl.mongodb.net/test?retryWrites=true&w=majority';
mongoose.connect(dbUrl ,{useNewUrlParser : true},(err) => {
if (err) {
console.log(err);
}
});
var schema = new mongoose.Schema({ name: 'string', message: 'string' });
var User = mongoose.model('User', schema);
//
// router
app.get('/', function(req, res) {
res.render('index');
});
app.use(express.json());
app.post('/send', [
check('name').isLength({ min: 1 }).withMessage('Անունը չի կարող դատարկ լինել'),
check('message').isLength({ min: 10 }).withMessage('Նամակը պետք է լինի 10 սիմվոլից ավել')
], (req, res) => {
// Uxarkel errornery
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.render('index',{
errors: errors
});
}
// Stexcel userin
User.create({
name: req.body.name,
message: req.body.message
}).then(user => res.json(user));
});
//
And here's the error that I'm getting:
(node:6244) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (C:\xampp\htdocs\node\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (C:\xampp\htdocs\node\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\xampp\htdocs\node\node_modules\express\lib\response.js:267:15)
at User.create.then.user (C:\xampp\htdocs\node\server.js:51:23)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:6244) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecti
ng a promise which was not handled with .catch(). (rejection id: 1)
(node:6244) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process wit
h a non-zero exit code.
I'm new to Node, so can you please explain what causes the error. Thanks.
if (!errors.isEmpty()) {
res.render('index',{
errors: errors
});
}
else {
// Stexcel userin
User.create({
name: req.body.name,
message: req.body.message
}).then(user => res.json(user))
}
The else part of code was getting executed, even if there was error, and it was trying to send the response again. thus you were getting that error. Or you can a return when you are sending error, it will resolve the issue.