I'm using Express and Sequelize to make a basic user authentication based upon this tutorial
When I want to sign a token to a user I get an error telling me I'm trying to JSON.stringify() a circular reference which cannot be done. Therefor an error is thrown and I can't assign the token to the user.
OR I am doing something wrong when finding my user in the database which makes a circular reference OR I just need to find a solution to break the circular reference I suppose. Anyone who could explain me which of the two it is?
The full error is:
TypeError: Converting circular structure to JSON
at Object.stringify (native)
at toString (/Users/Desktop/express-jwt/node_modules/jws/lib/tostring.js:9:15)
at jwsSecuredInput (/Users/Desktop/express-jwt/node_modules/jws/lib/sign-stream.js:12:34)
at Object.jwsSign [as sign] (/Users/Desktop/express-jwt/node_modules/jws/lib/sign-stream.js:22:22)
at Object.module.exports [as sign] (/Users/Desktop/express-jwt/node_modules/jsonwebtoken/sign.js:144:16)
at Model.User.findOne.then.user (/Users/Desktop/express-jwt/server/index.js:69:27)
at Model.tryCatcher (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/promise.js:510:31)
at Promise._settlePromise (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/promise.js:567:18)
at Promise._settlePromise0 (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/promise.js:612:10)
at Promise._settlePromises (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/promise.js:691:18)
at Async._drainQueue (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/async.js:138:16)
at Async._drainQueues (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/async.js:148:10)
at Immediate.Async.drainQueues (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:574:20)
at tryOnImmediate (timers.js:554:5)
My index for the server is:
const express = require(`express`);
const app = express();
const bodyParser = require(`body-parser`);
const morgan = require('morgan');
const jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
const config = require('./config'); // get our config file
const db = require(`./models`);
const User = global.db.User;
const port = process.env.PORT || 8080;
db.sequelize.sync().then(() => {
console.log(`Express server listening on port ${port}`);
});
app.set('superSecret', config.secret);
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use(morgan('dev'));
app.get('/', (req, res) => {
res.send('Hello! The API is at http://localhost:' + port + '/api');
});
app.listen(port);
console.log('Magic happens at http://localhost:' + port);
app.get('/setup', (req, res) => {
db.sequelize.sync().then(() => {
return User.create({
username: 'Kevin frafster',
password: 'password',
admin: true
})
.then(addedUser => {
console.log(addedUser.get({
plain: true
}));
})
.catch(err => {
res.json(err);
});
});
});
// API ROUTES -------------------
// get an instance of the router for api routes
const apiRoutes = express.Router();
apiRoutes.post('/authenticate', (req,res) => {
User.findOne({
where: {username: req.body.username}
}).then(user => {
if (!user) {
res.json({ success: false, message: 'Authentication failed. User not found.'});
}else{
// console.log(user);
if (user.password != req.body.password) {
res.json({ success: false, message: 'Authentication failed. Wrong password.' })
}else{
const token = jwt.sign(user, app.get('superSecret'), {
expiresIn: 60*60*24
});
res.json({
succes: true,
message: 'Enjoy your token!',
token
});
}
}
}).catch(err => {
res.status(500).json(err);
})
});
// TODO: route to authenticate a user (POST http://localhost:8080/api/authenticate)
// TODO: route middleware to verify a token
// route to show a random message (GET http://localhost:8080/api/)
apiRoutes.get('/', (req, res) => {
res.json({ message: 'Welcome to the coolest API on earth!' });
});
// route to return all users (GET http://localhost:8080/api/users)
apiRoutes.get('/users', (req, res) => {
User.findAll({})
.then(users => {
res.json(users);
})
.catch(err => {
res.json(err);
});
});
// apply the routes to our application with the prefix /api
app.use('/api', apiRoutes);
Well, the answer was totally peanuts.
1) Make new object and assign payload to it
const payload = {username: user.username, password: user.password};
2) Use the new object to assign token to
const token = jwt.sign(payload, app.get('superSecret'), {
expiresIn: 60*60*24
});
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 am working on a backend for a Online mediconsult app and I came across this error in the JWT authentication. Since I am a newbie I dunno much about this topic. I have this 3 routes on my NodeJS /register, /login, /appointments. I was able to hit "/register" and "/login" perfectly fine. But when I copy the JWT token generated by "/login" route and paste it 'authorization' header it throws the problem.
node:internal/errors:484
ErrorCaptureStackTrace(err);
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:393:5)
at ServerResponse.setHeader (node:_http_outgoing:644:11)
at ServerResponse.header (C:\Users\krish\Desktop\mrcooper-task\server\node_modules\express\lib\response.js:794:10)
at ServerResponse.send (C:\Users\krish\Desktop\mrcooper-task\server\node_modules\express\lib\response.js:174:12)
at module.exports.login (C:\Users\krish\Desktop\mrcooper-task\server\controllers\authController.js:62:7) {
code: 'ERR_HTTP_HEADERS_SENT'
}
Node.js v18.12.0
A strange thing is, when I restart the server again with the same auth token, it works!.
Wonder why would it hit the above error before restarting ?
Code
index.js
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const app = express();
require('dotenv').config();
//External routes
const authRoutes = require("./routes/authRoutes");
const appointRoutes = require("./routes/appointRoutes");
// Middlewares
app.use(cors());
app.use(express.json());
//DB connection
const dbURI =
process.env.DB_URL;
mongoose
.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then((result) =>
app.listen(8080, () =>
console.log("App sucessfully started on localhost port 8080")
)
)
.catch((err) => console.log(err));
//Internal routes
app.use(authRoutes);
app.use(appointRoutes);
appointRoutes.js
const { Router } = require("express");
const verify = require("./verifyToken")
const router = Router();
router.get("/appointments",verify, (req, res) => {
res.send({ message: "Appointment route" });
});
module.exports = router;
authRoutes.js
const { Router } = require("express");
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const { registerValidator, loginValidator } = require("../validation");
const router = Router();
router.post("/register", async (req, res) => {
//Validate data before creating a user
const { error } = registerValidator(req.body);
if (error) {
return res.status(400).send(error.details[0].message);
}
//Check if email already exists
const emailExists = await User.findOne({ email: req.body.email });
if (emailExists) {
return res.status(400).send("Email already exists");
}
const { name, email, password, catogery, DOB } = req.body;
//Hash password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
//console.log(hashedPassword);
try {
const user = await User.create({
name,
email,
password: hashedPassword,
catogery,
DOB,
});
res.status(201).json({ user: user._id });
} catch (err) {
//console.log(err);
res.status(400).send(err);
}
});
router.post("/login", async (req, res) => {
const { email, password } = req.body;
//Validate data before authenticating a user
const { error } = loginValidator(req.body);
if (error) {
return res.status(400).send(error.details[0].message);
}
//Check if email dosen't exists
const user = await User.findOne({ email: req.body.email });
if (!user) {
return res
.status(400)
.send("Email dosen't exists. Please register and try again");
}
//Passowrd is incorrect
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) return res.status(400).send("Invalid Passowrd");
//Create and assign JWT token
const token = jwt.sign({_id: user._id}, process.env.TOKEN_SECRET)
res.header('auth-token', token).send(token);
//console.log(email, password);
res.send("Logged In!");
});
module.exports = router;
Here's what I did
I did few googles and searches on this error and found out that this error mainly throws out when we return multiple response per cycle. I checked the code below and I did'nt see multiple response coming from neither /login route nor /appointments route. Would there be any response leaks from if conditions accidentaly?
When I exit from nodemon and start again with the same take generated, now it can hit the /appointment. I wonder how it works ?
You get error when function like this
if(statement){
res.send(something)
}
res.send(something)
because code is continue after res.send() function
You must fix it to
if(statement){
return res.send(something)
}
return res.send(something)
and your res.send function in authController.js:62:7
While creating matrixClient by using matrix-js-sdk, I am getting an error of TypeError: this.opts.request is not a function.
The error is at line no. 19. but don't understand the reason.
const express = require('express');
const sdk = require('matrix-js-sdk');
const app = express();
const port = 3000;
require('dotenv').config();
const BASE_URL = process.env.BASE_URL;
const ACCESS_TOKEN = process.env.ACCESS_TOKEN;
const USER_ID = process.env.USER_ID;
const PASSWORD = process.env.PASSWORD;
const matrixClient = sdk.createClient({
baseUrl: BASE_URL,
accessToken: ACCESS_TOKEN,
userId: `#${USER_ID}:matrix.org`,
});
app.get('/', async (req, res) => {
await matrixClient.startClient(); // error
matrixClient.once('sync', function (state, prevState, res) {
console.log(state); // state will be 'PREPARED' when the client is ready to use
});
res.send('hello');
});
// getAccessToken(USER_ID, PASSWORD);
function getAccessToken(userId, password) {
const client = sdk.createClient('https://matrix.org');
client
.login('m.login.password', { user: userId, password: password })
.then((response) => {
console.log(response.access_token);
})
.catch((err) => {
console.log('access_token error :', err);
});
}
app.listen(port, () => {
console.log(`app is listening at http://localhost:${port}`);
});
ERROR :
app is listening at http://localhost:3000
Getting saved sync token...
Getting push rules...
Attempting to send queued to-device messages
Got saved sync token
Got reply from saved sync, exists? false
All queued to-device messages sent
Getting push rules failed TypeError: this.opts.request is not a function
at MatrixHttpApi.doRequest (A:\matrix\matrix_node\node_modules\matrix-js-sdk\lib\http-api.js:741:23)
at MatrixHttpApi.requestOtherUrl (A:\matrix\matrix_node\node_modules\matrix-js-sdk\lib\http-api.js:620:17)
at MatrixHttpApi.request (A:\matrix\matrix_node\node_modules\matrix-js-sdk\lib\http-api.js:576:17)
at MatrixHttpApi.authedRequest (A:\matrix\matrix_node\node_modules\matrix-js-sdk\lib\http-api.js:524:33)
ix-js-sdk\lib\client.js:7283:22) at SyncApi.getPushRules (A:\matrix\matrix_node\node_modules\matrix-js-sdk\lib\sync.js:155:42) at SyncApi.sync (A:\matrix\matrix_node\node_modules\matrix-js-sdk\lib\sync.js:674:16)
at MatrixClient.startClient (A:\matrix\matrix_node\node_modules\matrix-js-sdk\lib\client.js:497:18) at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async A:\matrix\matrix_node\index.js:19:3
Waiting for saved sync before retrying push rules...
I am trying to create product using nodejs and mongodb through my api for ecommerce management inventory but getting error as validation, the following below are my code that I have used.
This is my mongoose.js code
// require the library
const mongoose = require('mongoose');
require('dotenv').config();
// connecting database
mongoose.connect(process.env.MONGO_CONNECT);
// aquire the connection
const db = mongoose.connection;
//on error
db.on('error', console.error.bind(console, 'error connecting to db'));
// on success
db.once('open', function(){
console.log('Successfully connected to the database');
})
// exporting db
module.exports = db;
this is my schema
const mongoose = require('mongoose');
// Schema for Product [fields: id, name, quantity] with timeStamps
const productSchema = new mongoose.Schema({
name:{
type: String,
required: true
} ,
quantity:{
type: Number,
required: true
}
},{timestamps:true})
const Product = mongoose.model('Product', productSchema);
// exporting schema
module.exports = Product;
this is my controllerproduct js file
const Product = require('../models/product');
// Fetch List of products
module.exports.list = async function(req, res){
try{
let product = await Product.find()
return res.status(200).json({
data:{
message: "Products",
products: product
}
})
}catch(err){
console.log('Error in fetching List of products',err);
return res.send('Error in fetching List of products'+ err);
}
}
// Create Product
module.exports.create = async function(req, res){
try{
let product = new Product({
name: req.body.name,
quantity: req.body.quantity,
});
await product.save()
return res.status(200).json({
data:{
message: "Product created",
products: product
}
})
}catch(err){
console.log('Error in creating product',err);
return res.send('Error in creating product'+ err);
}
}
// Delete Product
module.exports.delete = async function(req, res){
try{
let product= await Product.findById(req.params.id);
await product.remove();
return res.status(200).json({
data:{
message: "Product removed from list",
}
})
}catch(err){
console.log('Error in removing product',err);
return res.send('Error in removing product'+ err);
}
}
// Update quantity
module.exports.update = async function(req, res){
try{
let product= await Product.findById(req.params.id);
// Here using req.query to update quantity [NOTICE: using number for query]
let num = parseInt(req.query.number);
if(product.quantity + num < 0){
return res.status(200).json({
data:{
message: "Try Again! Product quantity could not be less then 0",
}
})
}else{
product.quantity = product.quantity + num
await product.save()
return res.status(200).json({
data:{
message: "Product Quantity updated successfully",
products: product
}
})
}
}catch(err){
console.log('Error in updating quantity of the product',err);
return res.send('Error in updating quantity of the product:::'+ err);
}
}
module.exports.home = async function(req, res){
try {
return await res.send('Hello Admin')
} catch (error) {
console.log('Error at home',err);
return res.send('Error at home page:'+ err);
}
}
this is main index.js file
const express = require('express');
const port = process.env.PORT||8800;
const app = express();
const db = require('./config/mongoose');
// To parse incoming requests
app.use(express.urlencoded());
// It parses incoming requests with JSON
app.use(express.json())
// making connection to index of route
app.use('/', require('./routes/index'))
// connecting to port
app.listen(port, function(err){
if(err){
console.log(`Error! connecting Port : ${err}`);
}
console.log(`Connected on Port : ${port}`);
})
I'm trying to create product through my Api using postman but I am getting this error, any help will be appreciated:
Aditya Kumar#DESKTOP-980JOV2 MINGW64 ~/nodews/ecommerce-Api
$ node index.js
body-parser deprecated undefined extended: provide extended option index.js:7:17
Connected on Port : 8800
Successfully connected to the database
Error in creating product Error: Product validation failed: name: Path `name` is required., quantity: Path `quantity` is required.
at ValidationError.inspect (C:\Users\Aditya Kumar\nodews\ecommerce-Api\node_modules\mongoose\lib\error\validation.js:49:26)
at formatValue (node:internal/util/inspect:782:19)
at inspect (node:internal/util/inspect:347:10)
at formatWithOptionsInternal (node:internal/util/inspect:2167:40)
at formatWithOptions (node:internal/util/inspect:2029:10)
at console.value (node:internal/console/constructor:324:14)
at console.log (node:internal/console/constructor:360:61)
at module.exports.create (C:\Users\Aditya Kumar\nodews\ecommerce-Api\controllers\product_controller.js:34:17)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
errors: {
name: ValidatorError: Path `name` is required.
at validate (C:\Users\Aditya Kumar\nodews\ecommerce-Api\node_modules\mongoose\lib\schematype.js:1346:13)
at SchemaString.SchemaType.doValidate (C:\Users\Aditya Kumar\nodews\ecommerce-Api\node_modules\mongoose\lib\schematype.js:1330:7)
at C:\Users\Aditya Kumar\nodews\ecommerce-Api\node_modules\mongoose\lib\document.js:2835:18
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
properties: [Object],
kind: 'required',
path: 'name',
value: undefined,
reason: undefined,
[Symbol(mongoose:validatorError)]: true
},
quantity: ValidatorError: Path `quantity` is required.
at validate (C:\Users\Aditya Kumar\nodews\ecommerce-Api\node_modules\mongoose\lib\schematype.js:1346:13)
at SchemaNumber.SchemaType.doValidate (C:\Users\Aditya Kumar\nodews\ecommerce-Api\node_modules\mongoose\lib\schematype.js:1330:7)
at C:\Users\Aditya Kumar\nodews\ecommerce-Api\node_modules\mongoose\lib\document.js:2835:18
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
properties: [Object],
kind: 'required',
path: 'quantity',
value: undefined,
reason: undefined,
[Symbol(mongoose:validatorError)]: true
}
},
_message: 'Product validation failed'
}
It might be due to a miss config of an HTTP request header, please make sure you are sending a valid JSON payload when calling the API by adding a application/json content-type header
Examples:
CURL
curl -X POST http://localhost:8000 -d '{"name": "Dummy", "quantity": 1}' -H "Content-Type: application/json"
Fetch
const res = await fetch('http://localhost:8000', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
});
req.body.name is most likely coming up as undefined . try logging it out to the console, if it is indeed undefined, then it may be due to some system error. you can try restarting your server or even your local machine.
the problem may also be from the request you are sending in postman. make sure that all the parameters are in the right place
So I know there are tons of similar questions out there, and I've read most of them in the past few days. However I didn't find any solution to my problem. The app is about users can post memories(cards) etc... Point is, when I create a new card with POST request, there is no problem, but when I want to sign up a user then all hell breaks loose and throws this error:
(node:2732) UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property 'firstName' of 'req.body' as it is undefined.
at signup (file:///E:/projects/personal/memories-app/backend/controllers/user.controller.js:39:13)
at Layer.handle [as handle_request] (E:\projects\personal\memories-app\backend\node_modules\express\lib\router\layer.js:95:5)
at next (E:\projects\personal\memories-app\backend\node_modules\express\lib\router\route.js:137:13)
I don't know that could be the problem, because other functions work so dunno really.
Here are the codes
server.js
import express from 'express';
import mongoose from 'mongoose';
import cors from 'cors';
import dotenv from 'dotenv';
import postRoutes from './routes/posts.routes.js';
import userRoutes from './routes/users.routes.js';
const app = express();
dotenv.config();
app.use(express.json({ extended: true }));
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use('/posts', postRoutes);
app.use('/users', userRoutes);
app.get('/', (req, res) => {
res.send('Hello to Memories API');
});
const PORT = process.env.PORT || 5000;
mongoose
.connect(process.env.CONNECTION_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() =>
app.listen(PORT, () => console.log(`Server running on port: ${PORT}`))
)
.catch((error) => console.log(error.message));
mongoose.set('useFindAndModify', false);
user.model.js
import mongoose from 'mongoose';
const userSchema = mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
id: { type: String },
});
export default mongoose.model('User', userSchema);
the sign up method from user.controller.js
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import User from '../models/user.js';
export const signup = async (res, req) => {
const { firstName, lastName, email, password, confirmPassword } = req.body;
try {
const existingUser = await User.findOne({ email });
if (existingUser)
return res.status(400).json({ message: 'User already exists' });
if (password !== confirmPassword)
return res.status(400).json({ message: "Passwords don't match" });
const hashedPassword = await bcrypt.hash(password, 12);
const result = await User.create({
email,
password: hashedPassword,
name: `${firstName} ${lastName}`,
});
const token = jwt.sign(
{ email: result.email, id: result._id },
'test',
{
expiresIn: '1h',
}
);
res.status(200).json({ result, token });
} catch (error) {
res.status(500).json({ message: 'Something went wrong.' });
}
};
and just to see the createPost method (which works) from post.controller.js
import PostMessage from '../models/postMessage.js';
import mongoose from 'mongoose';
export const createPost = async (req, res) => {
const post = req.body;
console.log(post);
const newPost = new PostMessage(post);
try {
await newPost.save();
res.status(201).json(newPost);
} catch (error) {
res.status(409).json({ message: error.message });
}
};
And there is no problem with the front-end because when I simply console.log the req, I can see the body, but if I were to clg the req.body, then it is undefined. I've tried it with postman also, but no luck.
I would appreciate any insight on this! Thanks in advance!
You need to swap the order of res and req in the signup function, replace:
export const signup = async (res, req) => {
by:
export const signup = async (req, res) => {
Your User model does not have a firstName, lastName, and confirmPassword types use { name, email, password, } = req.body to sign up a new user.
In your project frontend use
name email, password, confirmPassword to register a use and email, password to log users in.