Why is my REQ.body.imageURL undefined in PUT method? - javascript

I'm trying to write the back-end for a foodie review app. The problem I'm having is at the PUT method, when I'm trying to modify a certain post, the req.body does not contain the imageUrl if I do not modify the URL . When req.file exists (the image), then everything works, because I set up a new imageURL. For some reasons I get the userId, description and everything else back except the imageUrl.
Here is my code:
exports.modifySauce = (req, res, next) => {
let sauce = new Sauce({ _id: req.params._id });
if (req.file) {
const url = req.protocol + '://' + req.get('host');
req.body.sauce = JSON.parse(req.body.sauce);
sauce = {
_id: req.params.id,
name: req.body.sauce.name,
manufacturer:req.body.sauce.manufacturer,
mainPepper:req.body.sauce.mainPepper,
description: req.body.sauce.description,
imageUrl: url + '/images/' + req.file.filename,
heat: req.body.sauce.heat,
userId: req.body.sauce.userId
};
} else {
sauce = {
_id: req.params.id,
name: req.body.name,
manufacturer:req.body.manufacturer,
mainPepper:req.body.mainPepper,
description: req.body.description,
imageUrl: req.body.imageUrl,
heat: req.body.heat,
userId: req.body.userId
};
}
Sauce.updateOne({_id: req.params.id}, sauce).then(
() => {
res.status(201).json({
message: 'Sauce updated successfully!'
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};
More information, in my Repo.
And here is the front end repo.
https://github.com/OpenClassrooms-Student-Center/nem-stack-hot-takes

Related

In a MERN and Axios app, using the mongoose populate function, the field populates in the server/terminal but not on the front end

I am developing a MERN app with axios and trying to populate a field(songList) in a model (User) that is referencing the Schema.Types.ObjectId of another schema (Song).
The _id populates when I create a new Song appropriately.
I can see the entire referenced field is populated in the terminal server side with a console.log but the I cannot get the field to populate on the client side.
My Model; I am trying to populate songList.
const { Schema, model } = require('mongoose')
const bcrypt = require('bcrypt');
const userSchema = new Schema({
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
songList: [
{
type: Schema.Types.ObjectId,
ref: 'Song'
}
],
});
userSchema.pre('save', async function (next) {
if (this.isNew || this.isModified('password')) {
const saltRounds = 10;
this.password = await bcrypt.hash(this.password, saltRounds);
}
next();
});
userSchema.methods.isCorrectPassword = async function (password) {
return bcrypt.compare(password, this.password);
};
const User = model("User", userSchema);
module.exports = User;
My server side query, console.log(userSongs) and console.log(user.songList) shows the array of songs appropriately in the terminal:
//login
router.post('/login', async (req, res) => {
const username = req.body.username;
const password = req.body.password;
User.findOne({ username: username })
.populate({path: "songList"})
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
res.status(404).json({ message: 'User Not Found' });
}
const passwordIsValid = bcrypt.compareSync(
password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({ message: "Invalid Password" });
}
let userSongs = [];
for (let i = 0; i < user.songList.length; i++) {
userSongs.push(user.songList[i])
}
const accessToken = sign(
{ username: user.username, _id: user._id },
"importantsecret");
// res.json({
// token: accessToken,
// username: username,
// _id: user._id,
// songList: user.songList
// });
res.status(200).send({
token: accessToken,
username: username,
_id: user._id,
userSongs: userSongs
});
console.log(userSongs)
});
});
The client side request for the user information where I am hoping to see a populated songList with console.log(singleUser):
const [singleUser, setSingleUser] = useState({})
const [userSongs, setUserSongs] = useState([])
useEffect(() => {
Axios.get(`http://localhost:3001/api/user/${id}`).then((response) => {
setSingleUser(response.data)
})
}, [authState])
Client side login request.
const login = () => {
const data = { username: username, password: password };
Axios
.post("http://localhost:3001/api/user/login", data)
.then((response) => {
if (response.data.error) {
console.log(response.data.error)
} else {
localStorage.setItem('accessToken', response.data.token)
setAuthState({
username: response.data.username,
_id: response.data._id,
status: true
});
window.location.replace('/')
}
})
}
Here is where I create a new Song and add it to the user that is logged in.
router.post('/insert', (req, res) => {
const id = req.body.id;
const songTitle = req.body.songTitle;
const artist = req.body.artist;
const album = req.body.album;
Song.create({ songTitle: songTitle, artist: artist, album: album })
.then((song) => {
return User.findOneAndUpdate(
{ _id: id },
{ $addToSet: { songList: song._id } },
{ new: true }
)
})
.then((user) =>
!user
? res.status(404).json({
message: 'Song created, but found no user with that ID',
})
: res.json('Created the song')
)
.catch((err) => {
console.log(err);
res.status(500).json(err)
})
});
Any suggests on how I can get songList to populate using the populate() mongoose function is much appreciated.
Thank you,
Brandon
I've read articles on stack overflow, 'Mongoose 'populate' not populating",
"Mongoose .populate() not working correctly". Medium articles, and the mongoose documentation.
I've tried sending the user songs in the response back as res.json() and res.send(). The field shows up but is not populated.
I've tried being more specific with songList.songTitle and {path: "songList")
All of these show the field populated in the terminal but not on the front side.

How can I find a Post of a User?

Hello I want to find posts which user has made ..
I do my request with JWT Token:
###
http://localhost:8080/forum/getByOwnerID
Authorization: Bearer {{token}}
This is my create function :
exports.create = async (req, res) => {
const { forumName, forumDescription } = req.body;
const token = req.token;
const forumExist = await Forum.findOne({ forumName: req.body.forumName });
if(forumExist){
res.status(400).send("Forum Exists already.");
}
try{
const owner = await User.findOne({userID:token._id});
if (!forumName || !forumDescription) {
res.status(400);
throw new Error("Please Fill all the feilds");
return;
}
else {
const newForum = new Forum({ forumName, forumDescription,user: owner.userID });
newForum.user = owner;
const createdNote = await newForum.save();
res.status(201).json(createdNote);
}
}catch(err){
res.status(400).send(err);
}
};
This is my function where I want to get the Posts which the user has made :
exports.getByToken = async (req, res, next) => {
const forum = await Forum.findById( {user: req.token._id} );
if (forum) {
res.json(forum);
} else {
res.status(404).json({ message: "Forum not found" });
}
res.json(forum);
}
And this is model which I have for Post:
const forumSchema = ({
forumName: {
type: String,
required: true,
},
forumDescription: {
type: String,
required: true,
},
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
published_on: {
type: String,
default: moment().format("LLL")
},
});
Everytime I do a request it has this error :
UnhandledPromiseRejectionWarning: CastError: Cast to ObjectId failed for value "{ user: 'admin' }" (type Object) at path "_id" for model "Forum"
my generate Token :
const generateToken = (_id, userID) => {
console.log('Signing token for ID ', _id,userID);
console.log('Secret key is ', process.env.JWT_KEY);
const token = jwt.sign({ _id,userID}, process.env.JWT_KEY, {
expiresIn: "30d",
});
console.log('Signed token: ', token);
return token;
};
As you are using findById, you should only send the id as argument function.
If you want to search with filter query, use find method

error: MongoError: Performing an update on the path '_id' would modify the immutable field '_id'

I tried using const course ={....} instead of const course = new course({...}) and also removing the _id from it, but to no avail. I tried taking hints by using logger but that too didnt depict my issue.
course.js
router.put(
"/:id",
(req, res, next) => {
const course = new Course({
_id: req.body.id,
coursename: req.body.coursename,
duration: req.body.duration,
strength: req.body.strength
});
logger.trace('Details: ', course);
logger.trace(req.body);
Course.updateOne({ _id: req.params.id }, course).then(result => {
logger.trace('Result: ', result);
if (result.nModified > 0) {
res.status(200).json({ message: "Update successful!" });
}
else {
res.status(401).json({ message: "Access Denied!" });
}
})
.catch(err => {
console.log('error: ', err);
});
}
);
Here's the updatePosts() function of course.service.ts file that I use for linking with backend for course
updatePosts(id: string, coursename: string, duration: string, strength: number) {
let CData: courseData | FormData;
CData = new FormData();
CData.append("id", id);
CData.append("coursename", coursename);
CData.append("duration", duration);
CData.append("strength", strength.toString());
this.http
.put("http://localhost:3300/api/admin/courses/" + id, CData)
.subscribe(response => {
const updatedCourses = [...this.courses];
const oldPostIndex = updatedCourses.findIndex(p => p.id === id);
const post: courseData = {
id: id,
coursename: coursename,
duration: duration,
strength: strength
};
updatedCourses[oldPostIndex] = post;
this.courses = updatedCourses;
this.coursesUpdated.next([...this.courses]);
// this.router.navigate(["/"]);
});
}

Node JS Not Allowing Returned JSON into JSON String

I have written a Firebase cloud function to sign people up into my Firebase database. I have tested with POSTMAN and the function is working correctly.
The problem I am having is that I have a function that is getting a stripe ID and then needs to return that value. I want the customer id (customer.id in my reference) to append a JSON string I have created with the users info.
This way, when the function is done it needs to write all the data to firebase and then return the same JSON string variable to my app. This all works, but I cannot get the Stripe ID to append into my JSON array and be parsed.
I have been cowering the internet to try and find a solution, and I believe my syntax is correct, but its not working. I know the function is working because the console.log is outputting the stripe ID, its just not being added to the JSON variable that is being written to Firebase.
Anyone that could explain where I am going wrong would be much appreciated. I have referenced my issue points in the code below with // for comments.
exports.myCloudFunction=
functions.https.onRequest((req, res) => {
if (req.method !== 'POST') {
return;
}
const userDataInput = req.body;
console.log('Console Body:', req.body);
admin.auth().createUser({
email: userDataInput.email,
emailVerified: false,
phoneNumber: userDataInput.mobile,
password: userDataInput.password,
displayName: userDataInput.firstname + ' ' + userDataInput.lastname,
disabled: false
})
.then(async function (userRecord) {
console.log('User record:', userRecord);
var userObject = //CONSTRUCTED JSON STRING
{
first_name: userDataInput.firstname,
last_name: userDataInput.lastname,
mobile_number: userDataInput.mobile,
email: userDataInput.email,
timestamp: admin.database.ServerValue.TIMESTAMP,
driver_profile: { isDriverApproved: false, isDriverDisabled: false, isDriverStatusPending: false, isDriver: false, isPickupModeEnabled: false },
}
stripe.customers.create({
description: 'Firebase ID: ' + userRecord.uid,
email: userRecord.email,
name: userRecord.displayName,
phone: userRecord.phoneNumber
}, async function (err, customer) {
console.log('New Stripe ID Created', customer.id); // THIS WORKS< THE customer.id is outputting
try {
return userObject[{ stripe_id: customer.id }]; // THIS IS NOT WORKING, I WANT **customer.id** TO BE PUT INTO THE **userObject** JSON variable.
}
catch (error) {
console.error(error);
return res.status(200).send('Error: ' + error);
}
});
try {
await admin.database().ref('users/' + userRecord.uid).set(userObject);
return res.status(200).send({ returnData: userObject });
}
catch (error) {
console.error(error);
return res.status(200).send('Error: ' + error);
}
})
.catch(function (error) {
console.log('Error creating new user:', error);
res.status(500).send({ returnError: error });
});
});
I think that the return it won't return anything because is a callback
exports.myCloudFunction =
functions.https.onRequest((req, res) => {
if (req.method !== 'POST') {
return;
}
const userDataInput = req.body;
console.log('Console Body:', req.body);
admin.auth().createUser({
email: userDataInput.email,
emailVerified: false,
phoneNumber: userDataInput.mobile,
password: userDataInput.password,
displayName: userDataInput.firstname + ' ' + userDataInput.lastname,
disabled: false
})
.then(async function (userRecord) {
console.log('User record:', userRecord);
var userObject = //CONSTRUCTED JSON STRING
{
first_name: userDataInput.firstname,
last_name: userDataInput.lastname,
mobile_number: userDataInput.mobile,
email: userDataInput.email,
timestamp: admin.database.ServerValue.TIMESTAMP,
driver_profile: {
isDriverApproved: false,
isDriverDisabled: false,
isDriverStatusPending: false,
isDriver: false,
isPickupModeEnabled: false
},
}
stripe.customers.create({
description: 'Firebase ID: ' + userRecord.uid,
email: userRecord.email,
name: userRecord.displayName,
phone: userRecord.phoneNumber
}, async function (err, customer) {
console.log('New Stripe ID Created', customer.id); // THIS WORKS< THE customer.id is outputting
try {
// Move your logic to the final callback
userObject["stripe_id"] = customer.id;
await admin.database().ref('users/' + userRecord.uid).set(userObject);
return res.status(200).send({returnData: userObject});
} catch (error) {
console.error(error);
return res.status(200).send('Error: ' + error);
}
});
})
.catch(function (error) {
console.log('Error creating new user:', error);
res.status(500).send({returnError: error});
});
});
I think I found the error. There is an issue with your syntax
There is a line of code that is wrong
//replace
return userObject[{ stripe_id: customer.id }];
// for this
return userObject.stripe_id = customer.id;
Note: Try to separate your code better. It's kind of hard to read

API testing using postman

I am developing Rest APIs for some project and testing them using postman to send the data on my mLab server. But All I could get:
{
"error": {
"message": "ENOENT: no such file or directory, open 'C:\\Users\\Admin\\Desktop\\periodical API\\uploads\\2018-06-16T14:34:38.384Zhd-wallpaper-of-live.jpg'"
}
}
Here's my route code:
const mongoose = require("mongoose");
const Product = require("../models/product");
exports.products_get_all = (req, res, next) =>
{
Product.find()
.select("name price quantity date subject _id productImage")
.exec()
.then(docs => {
const response = {
count: docs.length,
products: docs.map(doc => {
return {
name: doc.name,
price: doc.price,
quantity: doc.quantity,
date: doc.date,
subject: doc.subject,
productImage: doc.productImage,
_id: doc._id,
request: {
type: "GET",
url: "http://localhost:3000/products/" + doc._id
}
};
})
};
res.status(200).json(response);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
exports.products_create_product = (req, res, next) => {
const product = new Product({
_id: new mongoose.Types.ObjectId(),
name: req.body.name,
price: req.body.price,
quantity: req.body.quantity,
date: req.body.date,
subject: req.body.subject,
productImage: req.file.path
});
product
.save()
.then(result => {
console.log(result);
res.status(201).json({
message: "Created product successfully",
createdProduct: {
name: result.name,
price: result.price,
quantity: result.quantity,
date: result.date,
subject: result.subject,
_id: result._id,
request: {
type: "GET",
url: "http://localhost:3000/products/" + result._id
}
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
exports.products_get_product = (req, res, next) => {
const id = req.params.productId;
Product.findById(id)
.select("name price quantity date subject _id productImage")
.exec()
.then(doc => {
console.log("From database", doc);
if (doc) {
res.status(200).json({
product: doc,
request: {
type: "GET",
url: "http://localhost:3000/products"
}
});
} else {
res
.status(404)
.json({ message: "No valid entry found for provided ID" });
}
})
.catch(err => {
console.log(err);
res.status(500).json({ error: err });
});
};
exports.products_update_product = (req, res, next) => {
const id = req.params.productId;
const updateOps = {};
for (const ops of req.body) {
updateOps[ops.propName] = ops.value;
}
Product.update({ _id: id }, { $set: updateOps })
.exec()
.then(result => {
res.status(200).json({
message: "Product updated",
request: {
type: "GET",
url: "http://localhost:3000/products/" + id
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
exports.products_delete = (req, res, next) => {
const id = req.params.productId;
Product.remove({ _id: id })
.exec()
.then(result => {
res.status(200).json({
message: "Product deleted",
request: {
type: "POST",
url: "http://localhost:3000/products",
body: { name: "String", price: "Number" }
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
I myself could not figure out the problem as I am a bit newbie on developing APIs.
On Linux servers ENOENT means
“No such file or directory”
said that the response you are getting is trying to let you know that,
The directory where you are trying to save, does not exist
The place of file you are looking for does not exist.
What I do recommend you is that you use your debugger tool to stop the execution before you try to get to the directory or where you try to read your file. That way you will understand where your code is failing.
Now many times when I get to this error, usually means that the directory does not exist but more frequently that you do no have permission to save the file.
Good luck, I hope it helps.
http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html

Categories

Resources