why I get an empty request body express - node.js

Router
router.patch("/fav/:id", getFav);
controller
const getFav = async (req, res) => {
const { favToadd } = req.body;
const { id } = req.params;
try {
const Users = await User.findById(id);
console.log("body : ", req.body); // body : {}
const fav = await User.findByIdAndUpdate(id, {
$set: { favorite: [...Users.favorite, favToadd] },
});
res.send(fav);
} catch (error) {
console.log("err ", error.message);
}
};
//Function to add favorites
const response = await fetch(
`http://localhost:4000/api/user/fav/${currentUser._id}`,
{
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prd: product.props }),
}
);
};
the item gets saved to MongoDB as null and then I take look at the req body it's empty,
my goal is to add an object to the favorite properties in MongoDB document
but it gets saved as null
try different methods but nothing works I don't think I get a body from the patch request
don't know if the problem with it or in the communication between the front and the back end it's
my first app so hopefully, the problem is in this line of code not in another part,
when I send it from postman with raw JSON it Works and gets saved at MongoDB with the properties I set

Related

How I do redirect using Express. EJS with external javascript?

I have a login form which is collect user email and password. Then I use JavaScript fetch to post data to express. then I use express validator check the inputs are correct. Then I send response res.status(200).redirect("/auth"); like this, but JavaScript is prevent the login page to redirect because in my external JavaScript I use e.preventDefault() function. But I want to redirect to next page. When I remove e.preventDefault() it stops the validation so I cant remove that. What should I do?
I'm using Node, Express Js, JSON file for storing Data, EJS Template with external JavaScript file. Aslo serving static JavaScript file too which is located in public/js/script.js file. Also using express-validator in middleware folder to validate the fields
Here is the express code:
export const loginsHandle = async (req, res) => {
const {
email,
password,
} = req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({
errors: errors.array(),
});
} else {
try {
var accountPP = new PP({
email: email,
password: password,
});
let addingData = JSON.parse(fs.readFileSync(accountDataFile, "utf-8"));
addingData.push(accountPP);
await fs.writeFileSync(accountDataFile, JSON.stringify(addingData));
res.status(200).redirect("/auth");
} catch (error) {
console.log(error);
res.status(200).send(error);
}
}
};
Here is external JavaScript :
const form = document.querySelector("form");
const emailInput = document.getElementById("email");
const passwordInput = document.getElementById("password");
const btn = document.getElementById("submit");
const forGot = document.getElementById("forgot");
const singBtn = document.getElementById("sign");
const footer = document.getElementById("menuFoot");
forGot.addEventListener("click", (e) => {
e.preventDefault();
});
singBtn.addEventListener("click", (e) => {
e.preventDefault();
});
footer.addEventListener("click", (e) => {
e.preventDefault();
});
form.onsubmit = sendLogin;
function sendLogin(e) {
e.preventDefault();
let formData = new FormData(form);
let Params = {
headers: {
"Content-Type": "application/json",
accept: "application/json",
},
body: JSON.stringify({
email: formData.get("email"),
password: formData.get("password"),
}),
method: "POST",
};
fetch("http://localhost:5001/login", Params)
.then((res) => {
return res.json();
})
.then((data) => {
if (data.errors) {
data.errors.forEach((err) => {
if (data.errors[0].param == "email") {
emailInput.style.borderColor = "red";
} else if (data.errors[0].param == "password") {
passwordInput.style.borderColor = "red";
} else {
emailInput.style.borderColor = "";
passwordInput.style.borderColor = "";
}
});
}
return data;
})
.catch((error) => console.log(error, "error"));
}
When you send a REST request using fetch() in the browser, the browser doesn't process the response. It's up to your code to look at the status code and body of the response and take any action that you need to. The browser will not change the URL based on the response.
My recommendation is to use 200 to indicate that the login was successful, and then in the browser code, navigate to /auth. In your server code, you should send a 500 status instead when there's an error.
To simulate a redirect, your best bet is to use location.replace (see How do I redirect to another webpage? for a discussion on why):
window.location.replace('/auth.html')

How can I upload an image and form data as well on a single button click?

I am making a practice project in MERN stack and wanted to upload images from react js with the form on single button click, so I needed to call two apis on just one button click. But I am having errors that's why I am unable to upload image and form data as well.
My react js code here:
const URL = "http://localhost:2040/add_recipe";
const formData = new FormData();
formData.append("recipe_image", selectedFile);
let config = {
headers: {
"Content-Type": "multipart/form-data",
authorization: JSON.parse(localStorage.getItem("token")),
},
};
axios
.post(URL, formData, config)
.then((response) => {
console.log("Image uploaded successfully" + response);
})
.catch((error) => {
console.log("Error while uploading image" + error);
});
and here is my backend api:
const Recipe = require("../models/Recipe");
const fs = require("fs");
let filePath = "";
const AddRecipe = async (req, res) => {
if (req.file) {
filePath = req.file.path;
}
console.log("filepath: " + filePath);
let recipee = await Recipe.findOne({ name: req.body.name });
if (recipee) {
res.json({ Response: "Recipe already exists!" });
} else {
if (
req.body.category &&
req.body.ptime &&
req.body.name &&
req.body.noOfPeople &&
req.body.shortDesc &&
req.body.recipe
) {
let recipe = await Recipe.create({
category: req.body.category,
ptime: req.body.ptime,
name: req.body.name,
noOfPeople: req.body.noOfPeople,
shortDesc: req.body.shortDesc,
recipe: req.body.recipe,
avatar: {
data: fs.readFileSync(filePath),
contentType: "image/png",
},
});
let result = await recipe;
console.log(filePath + " .......path");
if (result.name) {
res.json({ Response: "Recipe added successfully!" });
} else {
res.json({ Response: "Recipe not added!" });
}
}
}
};
module.exports = { AddRecipe };
This is how I called the api with multer already setup
app.post("/add_recipe", verifyToken, upload.single("recipe_image"), AddRecipe);
I found the answer, actually I had to sent all data using FormData inside the axios request and its content-type would be multipart/form-data.
So, the request should be one because url is same and we can send form data and image as well using FormData append method and on backend we can get image as req.file and data as req.body.*
That's all!

How to post a body correctly in Postman

I try to make a post request to an api but, api returns error. Although I thought about it for a long time, I could not find the cause of the error.
I think the error is due to not creating the body correctly because when I send empty array as items array the code works.
API DOCUMENTATION:
Here is my request:
module.exports.createOrder = (token, paymentId, items, callback) => {
const url = urlBase;
request(
{
url: url,
method: "POST",
json: true,
headers: {
"content-type": "application/json",
Authorization: `Bearer ${token}`,
},
body: {
secretKey: `${secretKey}`,
paymentId: paymentId,
items: items,
},
},
(error, response) => {
if (error) {
Sentry.captureException(error);
callback(errMessage, undefined);
} else {
const data = response.body;
callback(undefined, data);
}
}
);
};
Here is test values:
const testToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYyM2RmYjg4NDA4M2IwMDAyNDNjYzRhNyIsImlhdCI6MTY0ODIyOTI1NywiZXhwIjoxNjQ4MzE1NjU3fQ.9fgR3ei81vsHVMhSi8VwEyE2WMgFIMthm0PF9_zrqjw"
const paymentId = "pi_1Dq2f62eZvKYlo2Cy1moIb0G"
const variant = {
variations_values: {
color:'Black',
size:'42'
},
price:495,
product_id: "883360511078"
}
const productId = "82936941"
const quantity = 1
const item = {
variant:variant,
productId:productId,
quantity:quantity
}
let items = [item]
orderRequests.createOrder(testToken, paymentId, items, (err, data) => {
if(data){
console.log(data)
} else{
console.log(err)
}
})
I get internal server error as a response when I post these test values, but If I post an empty array as items, api does not return internal server error. What is the problem, any help?
Internal Server Error Response when I send an array with post body:
Expected request when I send an empty array with post body:

Using React, NodeJS, and Postgres: Having trouble being able to delete and updating todos

I am creating simple todo app with postgre and react.
The server side the delete and update are defined as below.
app.put("/todos/:id", async (req, res) => {
try {
const { id } = req.params;
const { description } = req.body;
const updateTodo = await pool.query(
"update todo set description = $1 where todo_id = $2",
[description, id]
);
res.json("todo updated !!");
} catch (error) {
console.error(error.message);
}
});
// delete todo
app.delete("/todos/:id", async (req, res) => {
try {
const { id } = req.params;
const deleteTodo = await pool.query("delete from todo where todo_id = $1", [
id,
]);
res.json("todo deleted !!");
} catch (error) {
console.error(error.message);
}
});
On the front end (React) this is how I am calling the update and delete
const updateDescription = async () => {
try {
handleClose();
const body = { description };
const response = fetch(`http://localhost:3000/${todo.todo_id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
console.log(response);
} catch (error) {
console.log(error.message);
}
};
Delete todo is in the other component.
const deleteTodo = async (id) => {
try {
const deleteTodo = await fetch(`http://localhost:3000/${id}`, {
method: "DELETE ",
});
console.log(deleteTodo);
setTodods(todos.filter((todo) => todo.todo_id !== id));
} catch (error) {
console.log(error.message);
}
};
So when I am doing delete or put request its not updating it in the DB.
On the browser console I am getting this error.
Failed to execute 'fetch' on 'Window': 'DELETE ' is not a valid HTTP method.
Edited
Response {type: "cors", url: "http://localhost:3000/3", redirected: false, status: 404, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 404
statusText: "Not Found"
type: "cors"
url: "http://localhost:3000/3"
__proto__: Response
For insert todo its working but for delete and put request its not updating in the database.
So can somebody tell me whats going wrong here ?
There is a space after DELETE, correct it should work properly. Even if its a simple todo App, its always good practice to create an enum or const when we are dealing with fixed string, i.e., we know the string would not change so that we can have consistency and skip over these kind of issues.
const METHOD = {
GET: "GET",
PUT: "PUT",
POST: "POST",
DELETE: "DELETE"
};

React/Express - Axios get request help needed

Trying to make an API get request from front-end (React) to back-end (Express/MongoDB) using Axios. If I use Postman to make the request it works fine (you can enter a user ID in the request body and get back an array of objects containing that user ID, which is what I want), but doing it from a front-end built in React doesn't work, I just get an empty array returned. As far as I can tell my API call from the front-end is exactly the same as the one I'm making in Postman! Can anyone shed any light on this?
This is the code making the get request from the front end:
const getActivities = async (currentUser) => {
const config = {
crossdomain: true,
headers: {
"Content-Type": "application/json"
},
body: {
"user": `${currentUser[0].id}`,
}
}
try {
const res = await axios.get('http://localhost:5000/api/activities', config)
console.log(res)
dispatch({
type: GET_ACTIVITIES,
payload: res.data
})
} catch (error) {
console.log(error)
}
}
And this is the route on the back-end handling this particular request:
router.get('/', async (req, res) => {
try {
const activities = await Activities.find({ user: req.body.user }).sort({ date: -1 })
if (!activities) {
res.json({msg: "Nothing found. Go forth and exercise!" })
}
res.json(activities).send()
} catch (err) {
res.send(err.message)
}
})
Thanks in advance!
You cannot send a request body with GET method see API AXIOS only for request methods 'PUT', 'POST', 'DELETE , and 'PATCH'.
for example if you want to keep a GET method use params
// React
const config = {
crossdomain: true,
headers: {
"Content-Type": "application/json"
},
params: {
user: `${currentUser[0].id}`,
}
}
try {
const res = await axios.get('http://localhost:5000/api/activities',config)
console.log(res.data)
}catch(err){
...
}
// Express
router.get('/', async (req, res) => {
console.log(req.query.user)
}

Resources