Multer + React + Nodejs Axios request - node.js

Axios Post request
// Create profile
export const createProfile = (profileData, avatar, history) => dispatch => {
dispatch(clearErrors());
const image = new FormData();
image.append("avatar", avatar, avatar.name);
axios
.post("/api/profile", image, profileData)
.then(res => history.push("/dashboard"))
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
Edit ---> Axios post request second attempt
// Create profile
export const createProfile = (profileData, avatar, history) => dispatch => {
dispatch(clearErrors());
const image = new FormData();
image.append("avatar", avatar, avatar.name);
image.append("user", profileData, profileData.username);
axios
.post("/api/profile", image)
.then(res => history.push("/dashboard"))
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
profileData is what i want in the req.body and avatar is what i receive in req.file in my back-end with multer, but what i receive is the req.file with the image but nothing in my req.body(Just an empty object)
This is my router in node
router.post(
"/",
upload.single("avatar"),
passport.authenticate("jwt", { session: false }),
(req, res) => {
console.log(req.body);
}
);

Try to implement in following way using FormData
handleSubmit(e)
{
e.preventDefault();
const err = this.validate();
if (!err) {
var formData = {
category: this.state.category,
course: this.state.course,
};
const { category, course } = this.state;
let fd = new FormData();
fd.append('Test', this.state.testFile, this.state.testFile.name);
fd.append('category', category);
fd.append('course', course);
console.log(fd);
axios({
method: 'post',
url: 'http://localhost:7777/api/uploadTest',
data: fd,
})
.then((response) => {
if (response.data == 'Success') {
alert('Test has been Added..!!');
}
else {
alert('Something went wrong');
this.setState({ category: '' });
}
// this.setState({success:'Alert: '+response.data});
})
.catch((e) => {
console.error(e);
this.setState({ success: 'Alert: Something went wrong' });
});
}
}

I consider your route as /api/profile in route file.
You don't show your header profileData.
It should be like this
const profileData = {
headers: { 'content-type': 'multipart/form-data' }
}
Then you can request to the server as you already did.

Related

How to store a cookie sent from Express server by using fetch API in React?

I'm trying to create signup Form using React, Express and MongoDB. I succeffuly implemented the post request and saved the user data in the database.
However,though the user is saved in the database, I failed to store ( see it the browser ) the jwt token using res.cookie('jwt',token).
I have a simple form made in React:
type Props = {
children: React.ReactNode;
};
export const SignupLayout = ({ children }: Props) => {
const user = {
email: 'alexy#gmail.com',
username: 'alexladies',
password: 'pasrfsfsdfgfdsd',
securityQuestion: "father's name",
securityAnswer: 'jhon',
joinedDate: '12-12-2023',
};
const handleSignup = async (event: React.SyntheticEvent) => {
event.preventDefault();
// The problem is here
await fetch('http://localhost:3000/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(user),
})
.then((reponse) => reponse.json())
.then((json) => console.log(json))
.catch((err) => console.log(err));
};
return (
<form
onSubmit={handleSignup}
method='post'
action='/signup'
className='sm:px-20 md:w-2/3 md:px-12 lg:w-1/2 lg:px-4 lg:my-4 xl:mt-16 xl:w-1/3 xl:px-16 mx-auto bg-white rounded-2xl py-10 text-center '
>
{children}
</form>
);
};
My express server:
const User = require('../../models/user');
const { handleError } = require('./error');
const { createToken } = require('../utils/token');
const getSignup = (req, res) => {
// It stores the cookie in the browser succesfully
res.cookie('name', 'value');
res.send('ok');
};
const postSignup = async (req, res) => {
// It failed to store the cookie in the browser !
const {
email,
password,
username,
securityQuestion,
securityAnswer,
joinedDate,
} = req.body;
const user = new User({
email,
password,
username,
securityQuestion,
securityAnswer,
joinedDate,
});
await user
.save()
.then(() => res.cookie('jwt', createToken(user._id)))
.then(() => res.status(200).json(user._id))
.catch((err) => {
res.status(400).json(handleError(err));
});
};
module.exports = { getSignup, postSignup };
I have tried to add:
credentials:'include'
But it does not work.
Sreenshot

Why is req.body empty {} (GET REQUEST)

This is my Frontend code
const fetchData = () => {
const options = {
method: 'GET',
url: 'http://localhost:1337/user/chart',
headers: {'x-access-token': sessionStorage.getItem('token')},
body: [chartData.datasets]
}
axios.request(options).then((response) => {
console.log(response)
}).catch((error) => {
console.error(error)})
}
This is backend
app.get('/user/chart', async (req, res) => {
const token = req.headers['x-access-token']
if (!token){
return res.status(404).json({ success: false, msg: "Token not found" });
}
try {
const decoded = jwt.verify(token, process.env.access_secret)
const email = decoded.email
await User.updateOne(
{ email: email },
{ $set: {} },
)
console.log(req.body)
return res.status(200).json({message: 'ok', label:[]})
} catch (error) {
console.log(error)
res.json({ status: 'error', error: 'invalid token' })
}
})
When I console.log(req.body) it is an empty {}.
Why is it empty?
I am using a GET request to retrieve the chart data
Axios API does not accept body on get get request you can send parameters with params example
const url = '/user/chart';
const config = {
headers: {'x-access-token': sessionStorage.getItem('token')},
params:{someKey:chartData.datasets}
};
axios.get(url, config)
Axios doesn't support setting a body for a get request, see the docs or this related question.
Though, I'd also recommend to reconsider your design. Typically the body isn't used in a GET request. If you're sending data to the server, you likely want to use POST or PUT instead. If you just want to pass a parameter, then you likely want to use request parameters.
If you absolutely need to send a body in your GET request, then you'll need to use a different tool.
frondend //
const fetchData = () => {
const options = {
method: 'POST',
url: 'http://localhost:1337/user/chart',
headers: {'x-access-token': sessionStorage.getItem('token')},
body: {name : "xx",mail:"xx#"}
}
axios.request(options).then((response) => {
console.log(response)
}).catch((error) => {
console.error(error)})
}
backend //
app.post('/user/chart', async (req, res) => {
const {name , mail} = req.body
const token = req.headers['x-access-token']
if (!token){
return res.status(404).json({ success: false, msg: "Token not found" });
}
try {
const decoded = jwt.verify(token, process.env.access_secret)
const email = decoded.email
await User.updateOne(
{ email: email },
{ $set: {} },
)
console.log(req.body)
return res.status(200).json({message: 'ok', label:[]})
} catch (error) {
console.log(error)
res.json({ status: 'error', error: 'invalid token' })
}
})Ï

Form Data doesn't show correctly when I send it via Fetch with Node & Muller & Mongoose & GirdFS

I'm trying to upload a new thumbnail with my new quiz, but I'm getting a type of error 500 with the message:
xhr.js:210 POST http://localhost:1234/api/user/61c17715dca0ed0006d92ff9/quizzes/create-quiz 500 (Internal Server Error)
I'm Using MERN stack and GridFS & Muller but I don't know what the error is:
Here is my api base:
const API_BASE_URL = "http://localhost:1234/api/user";
const { user_id, token } = authState.auth;
const client = axios.create({
baseURL: API_BASE_URL,
headers: {
"Content-type": "application/json",
Authorization: "Bearer " + token,
},
});
Here is my API:
export const createQuiz = (data) => async (dispatch) => {
let user = JSON.parse(localStorage.getItem("user"));
const { title, questions, thumbnail, description, category, purchaseCoins, privacy, difficulty } =
data;
const newObj = {
created_by: user.user_id,
title,
description,
category,
questions,
filename: thumbnail,
purchaseCoins,
privacy,
difficulty,
};
console.log("this is it:", newObj);
try {
const response = await api.createQuiz(newObj);
const data = await response.data;
window.location.href = "/dashboard/quizzes";
console.log(data)
dispatch({ type: CONST.ADD_QUIZ_SUCCEEDED, payload: data });
} catch (error) {
console.log(error)
dispatch({ type: CONST.ADD_QUIZ_FAILED, payload: error });
}
};
Here is my React code:
<input
className={styles._form_input}
type="file"
id="l-quiz-name"
name="image"
placeholder="Quiz Name"
onChange={(e) => {
e.preventDefault();
let newData = { ...quiz };
const formData = new FormData();
let currentlyUploaded = e.target.files[0];
formData.append(currentlyUploaded.name, currentlyUploaded);
newData["thumbnail"] = formData;
setQuiz(newData);
}}
/>;
And here is my route at the back:
router.post(
`${prefix}/create-quiz`,
userAuth,
upload.single("thumbnail"),
async (req, res) => {
try {
const user = await User.findOne({ _id: req.params.userId });
console.log(req.file.thumbnail)
const newQuiz = new Quiz({
purchaseCoins: req.body.purchaseCoins,
privacy: req.body.privacy,
created_by: req.params.userId,
category: req.body.category,
title: req.body.title,
description: req.body.description,
difficulty: req.body.difficulty,
questions: req.body.questions,
thumbnail: req.file.filename,
});
console.log(newQuiz);
await newQuiz.save();
user.quizzes.push(newQuiz._id);
await user.save();
return res.status(201).json({
message: "Finally , a quiz created properly !",
success: true,
});
} catch (error) {
return res.status(500).json({
message: "Can't save this quiz try again, check if it already exists",
success: false,
});
}
}
);
And this is the data on how the object is being sent to NodeJS:

How to POST and GET from mongoDB express server in react hooks?

I am getting an error to GET data from my API endpoint.
I am able to send data and also update/ delete them from the postTodo()method.
I have added it in a useEffect()so that the I am able to send data to server whenever a Todo is completed or deleted.
But whenever i reload the page, in the devtools, the todos array is [].
Some help would be appreciated.Thanks.
The Todo.jsx
const postTodo = (todos) => {
console.log(todos);
axios.post("http://localhost:4000/api/todos", todos, {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
}
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})
}
useEffect(() => {
postTodo(todos)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [todos])
useEffect(() => {
axios.get("http://localhost:4000/api/todos", {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
}
})
.then(res => {
console.log(res);
setTodos(res.data.todos)
})
.catch(err => {
console.log(err);
})
}, [])
the server.js
const authCheck = (req, res, next) => {
if (req.headers['authorization']) {
const token = req.headers['authorization'].split(" ")
if (token[0] !== 'Bearer') {
return res.send({ status: 'error', error: 'invalid request' });
} else {
req.jwt = jwt.verify(token[1], process.env.jwtSECRET);
return next();
}
}
}
app.post("/api/todos", authCheck, async (req, res) => {
const todos = req.body
console.log(todos);
const { id } = req.jwt
const user = await User.findByIdAndUpdate(id, { "todos": todos })
// console.log(user);
})
app.get("/api/todos", authCheck, async (req, res) => {
const { id } = req.jwt
const user = await User.findById(id)
log(user) //user.todos is empty
res.send({
status: "ok", todos: user.todos })
})
You can try something like this, where use effect for todos will log the value everytime you create a new todo
const postTodo = (todos) => {
console.log(todos);
axios.post("http://localhost:4000/api/todos", todos, {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
}
})
.then(res => {
console.log(res);
getTodos()
})
.catch(err => {
console.log(err);
})
}
const getTodos = () => {
axios.get("http://localhost:4000/api/todos", {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
}
})
.then(res => {
console.log(res);
setTodos(res.data.todos)
})
.catch(err => {
console.log(err);
})
}
const newTodo = () => {
const allTodos = [...todos];
allTodos.push("new Todo at:" + new Date())
postTodo(allTodos)
}
useEffect(() => {
console.log('todo-list', todos)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [todos])
useEffect(() => {
getTodos()
}, [])
return (<button onClick={() => }> Add Todo </button>)
The problem was solved,
actually it was the useEffect() issue.
I removed the UseEffect
and added the postTodos method after every useState hook updation.

req.session is not persistent on browser?

So I have a very typical query.
I am new to this and I am building a simple login web app using node and express-session which are stored in MongoDB.
Here is my code:
sessionRouter.post("", async(req, res) => {
try {
const user = await User.findByCredentials(
req.body.email,
req.body.password
);
if (user) {
const sessionUser = sessionizeUser(user);
req.session.user = sessionUser;
console.log(req.session.id);
res.send(req.session.user);
} else {
throw new Error("invalid details.");
}
} catch (e) {
res.status(400).send(e);
}
});
//route to logout
sessionRouter.delete("", ({
session
}, res) => {
try {
const user = session.user;
if (user) {
console.log(session.id);
session.destroy((err) => {
if (err) console.log(err);
res.clearCookie(process.env.SESS_NAME);
res.send(session.id);
});
} else {
throw new Error("Something went wrong");
}
} catch (err) {
console.log("things went wrong!");
//res.status(422).send(JSON.stringify(err));
}
});
I am storing a 'user' attribute to req.session when I call the login API but when I call the logout API it generates a totally new session!.
Things go smoothly when I use postman to call these endpoints but when using a browser nothing works.
These are the calling functions I am using in browser:
const loggerin = () => {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Connection", "keep-alive");
var raw = JSON.stringify({
email: "xxxxxxxxxx",
password: "xxxxxx",
});
var requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow",
};
fetch("http://localhost:3001/api/session", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
};
const loggerout = () => {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Connection", "keep-alive");
var requestOptions = {
method: "DELETE",
};
fetch("http://localhost:3001/api/session", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
};
const test = () => {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Connection", "keep-alive");
var requestOptions = {
method: "GET",
};
fetch("http://localhost:3001/api/session", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
};
Please help!!! Thanks in advance!
The issue was that I was creating the session in the wrong function. I corrected that and it worked.

Resources