Resolving UnhandledPromiseRejectionWarning in express post request - node.js

I am trying to make a post request to the server (mongodb) but I get this error:
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'todo_description' of undefined
I am running mongodb on my localhost
// Require Express
const express = require("express");
// Setting Express Routes
const router = express.Router();
// Set Up Models
const Todo = require("../models/todo");
// Get All Todos
router.get("/", async (req, res) => {
try {
const todo = await Todo.find();
res.json(todo);
} catch (err) {
res.json({ message: err });
}
});
router.get("/:id", async (req, res) => {
try {
const id = req.params.id;
await Todo.findById(id, (err, todo) => {
res.json(todo);
});
} catch (err) {
res.json({ message: err });
}
});
router.post("/add", async (req, res) => {
const todo = new Todo({
todo_description: req.body.todo_description,
todo_responsible: req.body.todo_responsible,
todo_priority: req.body.todo_priority,
todo_completed: req.body.todo_completed,
});
try {
await todo.save();
res.json(todo);
} catch (err) {
res.json({ message: err });
}
});
router.patch("/update/:id", async (req, res) => {
try {
const updateTodo = await Todo.updateOne(
{ _id: req.params.id },
{ $set: { todo_description: req.body.todo_description } }
);
updateTodo.save().then(updateTodo => {
res.json(updateTodo);
});
} catch (err) {
res.json({ message: err });
}
});
router.delete("/delete/:id", async (req, res) => {
try {
const deleteTodo = await Todo.deleteOne({ _id: req.params.id });
res.json(deleteTodo);
} catch (err) {
res.json({ message: err });
}
});
module.exports = router;
my todo model
// Require Mongoose
const mongoose = require("mongoose");
// Define Schema
// const Schema = new mongoose.Schema;
// Define Todo-Schema
const TodoSchema = new mongoose.Schema({
// Creating Fields
todo_description: {
type: String
},
todo_responsible: {
type: String
},
todo_priority: {
type: String
},
todo_completed: {
type: Boolean
},
todo_date: {
type: Date,
default: Date.now
}
});
// Compile Model From Schema
// const TodoModel = mongoose.model("Todos", TodoSchema);
// Export Model
module.exports = mongoose.model("todos", TodoSchema);
error message:
(node:548) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'todo_description' of undefined
at router.post (C:\Users\kinG\Desktop\projects\mountain-of-prototype\mern\backend\routes\todo.js:33:32)
at Layer.handle [as handle_request] (C:\Users\kinG\Desktop\projects\mountain-of-prototype\mern\backend\node_modules\express\lib\router\layer.js:95:5)
thank you

You are accessing todo_description from req.body. req.body will only be available if you add the body-parser middleware or add a similar one yourself.
Add this right before your routes are loaded :
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
app.use(bodyParser.json());
You can also add this to a specific route. Read more about it here.

You should use body-parser in your master file of the application. Which gives you the parsed json before your middle-ware parse the body, which by-default in string. And also make sure you are sending todo_description in the req.body(should check before use).
const bodyParser = require('body-parser');
app.use(bodyParser.json());

Related

Await on findOne returns not found (404) all the time

the below code returns not found (404) all the time. But the console logs the data as expected.
I am using Node, Koa, and Mongoose.
the server.js
const Koa = require('koa');
const bodyparser = require('koa-bodyparser');
const UserRoutes = require('./router/user.routes');
const TrustRoutes = require('./router/trust.routes');
const auth = require('./middleware/auth');
const app = new Koa();
require('dotenv').config();
require('./db');
app.use(bodyparser());
app.use(auth);
app.use(
TrustRoutes.routes()
).use(TrustRoutes.allowedMethods());
app.use(
UserRoutes.routes()
).use(UserRoutes.allowedMethods());
app.listen(process.env.PORT || 3000);
trust.routes.js
const router = new Router({
prefix: '/trust'
});
router.get('/:trustId', async (ctx,next) => {
let id = ctx.params.trustId;
let trust = await Trust.findById(id);
console.log(trust);
ctx.response.body = {
status: true,
message: 'Trust info',
data: trust
};
console.log('trust info');
next();
});
module.exports = router
the console logs the below details
{
_id: new ObjectId("61ed34100ebd7c8fbdbef596"),
name: 'new trust',
description: 'match',
contact: { email: 'gmail#gmail.com', phone: '90334' },
isActive: true,
createdAt: 2022-01-23T10:55:12.866Z,
updatedAt: 2022-01-23T10:55:12.866Z,
__v: 0
}
trust info
and the middleware (I suspect in here)
require('dotenv').config();
const jwt = require("jsonwebtoken");
const User = require("../models/user")
const except = [
'/user/login'
];
const verifyToken = async (ctx, next) => {
if (except.indexOf(ctx.request.path) >= 0) return next();
let token = (
ctx.request.body.token || ctx.request.query.token ||
ctx.request.headers["authorization"]
);
if (!token) {
ctx.response.status = 403;
ctx.body = {
status: false,
message: 'Unauthorized'
}
return;
}
token = token.replace(/^Bearer\s+/,'');
try {
const decoded = jwt.verify(token, process.env.TOKEN_KEY);
const user = await User.findOne({
email: decoded.username
},{password: 0});
ctx.request.user = user;
} catch (err) {
ctx.response.status = 403;
ctx.body = {
status: false,
message: 'Unauthorized'
}
return;
}
next();
};
module.exports = verifyToken;
I know that something in here is not correct but hard to understand since it's my first time on these async and koa with middleware please help me out on this.
the postman
You don't export anything from your router-file. In order to use
app
.use(TrustRoutes.routes())
.use(TrustRoutes.allowedMethods());
you need to export the koa-router from the TrustRoutes-file:
const router = new Router({
prefix: '/trust'
});
router.get('/:trustId', async (ctx,next) => {
// ...
});
module.exports = router;
Apart from this when using async handlers, you need to either return next or await (see https://github.com/ZijianHe/koa-router/issues/476):
router.get('/:trustId', async (ctx,next) => {
// ...
return next(); // or await next();
});
I missed to have return next() in auth js the middleware.
After updating it next(); to return next() it works.
const verifyToken = async (ctx, next) => {
.....
return next();
};

node js : test rest API

i'm new learner in backend node js ... in my code below i created an API for questions and it contains get,post,delete and edit
i wanted to test it using the extension rest client in VS code but when i type Get http://localhost:3000/api in route.rest file to test it,it stucks on waiting
is there a way to know if my API works good and can somebody please help me if i have mistake below?
thanks in advance
//server.js
// #ts-nocheck
const express = require('express');
const morgan = require('morgan');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const jwt = require('jsonwebtoken');
const questionRoutes = require('./routes/subscribers');
const cors = require('cors');
const http = require('http');
// Has to be move but later
const multer = require("multer");
const Question = require('./models/subscriber');
// express app
const app = express();
// Explicitly accessing server
const server = http.createServer(app);
// corsfffffffff
app.use(cors());
dotenv.config();
const dbURI = process.env.MONGO_URL || "mongodb://localhost:27017/YourDB";
mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(result => server.listen(process.env.PORT || 3000) )
.catch(err => console.log(err));
// register view engine
app.set('view engine', 'ejs');
app.use(express.json);
// middleware & static files
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));
app.use(morgan('dev'));
app.use((req, res, next) => {
res.locals.path = req.path;
next();
});
// routes
// question routes
app.use('/questions' , questionRoutes );
// 404 page
app.use((req, res) => {
res.status(404).render('404', { title: '404' });
});
//questionRoute.js
const express = require('express');
const questionController = require('../controllers/questionCon');
const questionApiController = require('../controllers/questionApiController');
const router = express.Router();
// API Routing
router.get('/api/', questionApiController.get_questions);
router.post('/api/add', questionApiController.create_question);
router.get('/api/:id', questionApiController.get_question);
router.delete('/api/delete/:id', questionApiController.delete_question);
router.put('/api/update/:id', questionApiController.update_question);
// EJS Routing for GUI
router.get('/create', questionController.question_create_get);
router.get('/', questionController.question_index);
router.post('/', questionController.question_create_post);
router.get('/:id', questionController.question_details);
router.delete('/:id', questionController.question_delete);
module.exports = router;
//question.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const questionSchema = new Schema({
questionTitle: {
type: String,
required: true,
},
description: {
type: String,
},
price: {
type: Number,
},
});
const Question = mongoose.model('Question', questionSchema);
module.exports = Question;
//questionAPIcontroller
const Question = require('../models/subscriber');
const validators = require('../validators');
let questionApiController = {
// Get a single question
get_question : async (req , res) => {
const id = req.params.id;
try {
const question = await Question.findById(id,(err, question) => {
if (err) return res.status(400).json({response : err});
res.send("hello")
res.status(200).json({response : question})
console.log("hello")
})
} catch (err) {
res.status(400).json(err);
}
},
// Get all the questions
get_questions: async (req , res) => {
try {
const questions = await Question.find((err, questions) => {
if (err) return res.status(400).json({response : err});
res.status(200).json({response : questions})
})
} catch (err) {
res.status(400).json(err);
}
},
// Create a question
create_question : async (req , res) => {
const {error} = validators.postQuestionValidation(req.body);
if(error) return res.status(400).json({ "response" : error.details[0].message})
try {
const question = await new Question(req.body);
question.save((err, question) => {
if (err) return res.status(400).json({response : err});
res.status(200).json({response : " Question created Successfully"})
});
} catch (err) {
res.status(400).json(err);
}
},
// Delete question
delete_question : async (req , res) => {
const id = req.params.id;
var questionExist = false;
var userId ;
const question = await Question.findById(id).then(result => {
questionExist = true;
userId = result.owner;
}).catch(err => {
questionExist = false;
res.status(400).json({response : err });
});
if(questionExist){
try {
Question.findByIdAndRemove(id ,(err, question) => {
// As always, handle any potential errors:
if (err) return res.json({response : err});
// We'll create a simple object to send back with a message and the id of the document that was removed
// You can really do this however you want, though.
const response = {
message: "Question successfully deleted",
id: question._id
};
return res.status(200).json({response : response });
});
} catch (err) {
res.status(400).json(err);
}
}
else {
return res.status(400).send( { "response" : "A question with that id was not find."});
}
},
// Update question
update_question : async (req , res) => {
const id = req.params.id;
Question.findByIdAndUpdate(id,req.body,
function(err, result) {
if (err) {
res.status(400).json({response : err});
} else {
res.status(200).json({response : "Question Updated"});
console.log(result);
}
})
},
// Get question's questions
}
module.exports = questionApiController
//questionController
const Question = require('../models/subscriber');
const question_index = (req, res) => {
Question.find().sort({ createdAt: -1 })
.then(result => {
res.render('index', { questions: result, title: 'All questions' });
})
.catch(err => {
console.log(err);
});
}
const question_details = (req, res) => {
const id = req.params.id;
Question.findById(id)
.then(result => {
res.render('details', { question: result, title: 'Question Details' });
})
.catch(err => {
console.log(err);
res.render('404', { title: 'Question not found' });
});
}
const question_create_get = (req, res) => {
res.render('create', { title: 'Create a new question' });
}
const question_create_post = (req, res) => {
const question = new Question(req.body);
question.save()
.then(result => {
res.redirect('/questions');
})
.catch(err => {
console.log(err);
});
}
const question_delete = (req, res) => {
const id = req.params.id;
Question.findByIdAndDelete(id)
.then(result => {
res.json({ redirect: '/questions' });
})
.catch(err => {
console.log(err);
});
}
module.exports = {
question_index,
question_details,
question_create_get,
question_create_post,
question_delete
}
change code
app.use(express.json);
to
app.use(express.json());

How can I make a post request inside another request using node js, express

I made an application to make push notifications and I succeeded in sending notifications. But I have a problem, which is that I want to save any notification that I send in my database,
Here is the code,
var FCM = require("fcm-node");
const express = require("express");
const mongoose = require("mongoose");
require("dotenv/config");
const app = express();
app.use(express.json());
const notificationSchema = mongoose.Schema({
name: String,
});
const NotificationModel = mongoose.model("Notification", notificationSchema);
app.post("/fcm", async (req, res, next) => {
try {
let fcm = new FCM(process.env.SERVER_KEY);
let message = {
to: req.body.token,
notification: {
title: req.body.title,
body: req.body.body,
},
};
fcm.send(message, function (err, response) {
if (err) {
next(err);
} else {
// res.json(response);
// res.send(message.notification.body);
app.post("/notfs", async (req, res) => {
let newNotf = new NotificationModel({
name: message.notification.body,
});
newNotf = await newNotf.save();
res.send(newNotf);
});
}
});
} catch (error) {
next(error);
}
});
app.get("/notfs", async (req, res) => {
const notfs = await NotificationModel.find();
res.send(notfs);
});
mongoose
.connect(process.env.CONNECTION_STRING)
.then(() => {
console.log("connected");
})
.catch((err) => {
console.log(err);
});
app.listen(3000, () => {
console.log("listened");
});
Why doesn't it save notifications in the database?
Another question
Please if there is a better way than this please leave it and thank you٫
Thanks in advance
use axios package, which is recommended by nodejs official.
Its simple like jquery ajax call

MongoDB & Mongoose, Save Nested Array of Objects - Node.js

I'm trying to save a nested array of objects to my MongoDB collection but the app is only saving the first object in the nested BankAccountsArray, I've tried using the .markModified() method but haven't got any success. I've attached the data accepted from the frontend part + my model schema + the route, Thanks for the help!
Frontend Data Accepted:
{
companyHoldingPercentage: '10%',
BankAccountsArray: [
{
bankAccountNumber: '32',
bankBranchNumber: '55',
bankName: 'abc'
},
{
bankAccountNumber: '3123',
bankBranchNumber: '412',
bankName: 'cde'
}
]
}
Model:
const mongoose = require("mongoose");
const BankAccountsArraySchema = mongoose.Schema({
bankName: String ,
bankBranchNumber: String ,
bankAccountNumber: String
}
);
const BankAccountsIndexSchema = mongoose.Schema({
companyHoldingPercentage: String ,
BankAccountsArray: [BankAccountsArraySchema]
});
module.exports = mongoose.model(
"bank-accounts-object",
BankAccountsIndexSchema
);
Route:
var express = require("express");
var router = express.Router();
const BankAccountsIndexModel = require("../Models/BankAccountsIndexModel");
router
.route("/BankAccountsIndexRoute")
.get(async (req, res, next) => {
BankAccountsIndexModel.find((err, collection) => {
if (err) {
console.log(err);
} else {
res.json(collection);
}
});
})
.post(async (req, res, next) => {
console.log(req.body);
const {
companyHoldingPercentage,
BankAccountsArray: [{ bankName, bankBranchNumber, bankAccountNumber }],
} = req.body;
try {
const NewBankAccountsIndexModel = new BankAccountsIndexModel({
companyHoldingPercentage,
BankAccountsArray: [{ bankName, bankBranchNumber, bankAccountNumber }],
});
NewBankAccountsIndexModel.markModified(req.body.BankAccountsArray);
NewBankAccountsIndexModel.save();
// res.json(bankAccount);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
})
module.exports = router;
Can you try to refactor your .post() endpoint like this:
.post(async (req, res, next) => {
try {
let new_bank_account = await BankAccountsIndexModel.create(req.body);
res.status(200).json(new_bank_account);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
})

How do I Solve Express Validator Middleware Error?

First, I have userController like this:
File userController.js
const { validationResults } = require('express-validator');
const { userSignUpValidation } = require('../validator/userSignUpValidate');
function userCreation(req, res) {
try{
const errors = validationResults(req);
if(errors) {
return res.status(400)
.json({
error: {
message: errors.array()[0].msg
}
})
}
bcrypt.hash(req.body.userPassword, saltRounds, function(err, hash) {
User.create({
userId: req.body.userId,
userEmail: req.body.userEmail,
userPhoneNumber: req.body.userPhoneNumber,
userPassword: hash
})
.then((user) => {
return res.status(200).json(user);
})
.catch((error) => {
return res.status(400).json.error;
});
});
} catch(error) {
return res.status(400)
.json({
error: {
message: error
}
})
}
}
In the validator/userSignUpValidate.js the code like this:
'use strict'
const { check } = require('express-validator');
module.exports = [
check('userId').isLength({ min: 5 }).withMessage('The username at least more than 5 characters!'),
check('userPassword').isLength({ min: 6 }).withMessage('The password at least more than 6 characters!'),
check('userPhoneNumber').isLength({ min: 10 }).withMessage('The phone number at least more than 10 characters!'),
check('userEmail').isEmail().withMessage('Is your email correct? Please be correct!')
]
When I test it on postman, the json response always show error by catch on userController.js without error message.
{
"error": {
"message": {}
}
}
My question. To ensure the express-validator run in the right place, where should I put the code?
Firstly you need to import validationResult from express-validator, in your code you are importing validationResults.
Secondly, you are not using your userSignUpValidate middleware. This middleware can be used in controller but it is better to appy it in the userRoute to keep controller clean.
So let's apply userSignUpValidate middleware to the userRoutes.
If the file paths don't match yours, please fix them.
const express = require("express");
const router = express.Router();
const usersController = require("../controllers/userController");
const userSignUpValidate = require("../validator/userSignUpValidate");
router.post("/register", [userSignUpValidate], usersController.userCreation);
module.exports = router;
Then in the controller, we need to import validationResult from express-validator and use it:
const { validationResult } = require("express-validator");
function userCreation(req, res) {
try {
const errors = validationResult(req);
if(!errors.isEmpty()) {
console.log(errors);
return res.status(400).json({
error: {
message: errors.array()[0].msg
}
});
}
//other code you have
} catch (error) {
return res.status(400).json({
error: {
message: error
}
});
}
}
exports.userCreation = userCreation;
When we send a request body with a 3 character password like this:
{
"userId": "userid",
"userPassword": "123",
"userPhoneNumber": "1234567890",
"userEmail": "abc#gmail.com"
}
The response will be like this with a 400 - Bad Request:
{
"error": {
"message": "The password at least more than 6 characters!"
}
}
you should pass like this
const errors = validationResults(req.body);
const Joi = require('#hapi/joi');
const loginValidation = data =>{ const schema = {
username: Joi.string().min(5).required(),
password: Joi.string().min(5).required(),
deviceId: Joi.string().min(2).required()
};
return Joi.validate(data, schema); };
module.exports.loginValidation = loginValidation;
My Routes File
const { registerValidation, loginValidation } = require('../../validation'); router.post('/login', async (req, res)=>{
try {
//validate the data to be submitted
const { error } = loginValidation(req.body);
if (error) return res.status(200).send(
{
status: 0,
message: "Validarion Error",
details: error.details[0].message
});
} catch (error) {
res.status(400).send({
status: 0,
message: "Failed",
error: error
});
}});
this code works fine and is in production mode
Just try like below,
const express = require('express');
const { check, oneOf, validationResult } = require('express-validator');
const app = express();
//this function you need to export in controller
const xxx = (req, res, next) => {
try {
validationResult(req).throw();
res.status(200).send('success');
} catch (err) {
console.log('error messagecame')
res.status(422).json(err);
}
}
app.get('/', oneOf([
check('lang').isIn(['js', 'react', 'angular'])
]), xxx);
app.listen(4000, ()=>{
console.log("running server 4k")
})
Sample working copy
UPDATE 2
I hope below one will help full,
const express = require('express');
const { check, oneOf, validationResult } = require('express-validator');
const app = express();
const xxx = [
check('lang').isIn(['js', 'react', 'angular']),
(req, res, next) => {
try {
validationResult(req).throw();
res.status(200).send('success');
} catch (err) {
console.log('error messagecame')
res.status(422).json(err);
}
}
]
app.get('/', xxx);
app.listen(4000, ()=>{
console.log("running server 4k")
})
SAMPLE WORKING COPY2
Error
https://TruthfulWeirdIrc--five-nine.repl.co?lang=jssddf
Success
https://TruthfulWeirdIrc--five-nine.repl.co?lang=js

Resources