I have a component with a Formik form for creating a new comment.
On the back, the comment needs PostId, UserId and text.
When I try to post, my console.logs on front return all the data, but I get an "error 400, Comment.UserId and Comment.PostId cannot be null" and the back receives all data undefined.
How it's possible?
If this data was undefined, all console.log should return undefined too, right?
CommentForm:
function newComment(values) {
const formData = new FormData();
formData.append("firstName", firstName);
formData.append("lastName", lastName);
formData.append("UserId", UserId);
formData.append("PostId", PostId);
formData.append("text", values.text);
console.log("UserId", UserId);
console.log("firstName", firstName);
console.log("lastName", lastName);
console.log("PostId", PostId);
console.log("text", values.text);
console.log(props.id);
axios({
method: "post",
url: `http://localhost:8000/api/comments/${props.id}`,
data: formData,
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${AuthState.token}`,
},
})
.then((res) => {
if (res.status === 201) {
console.log("Success");
window.location.reload(true);
}
})
.catch(function (error) {
console.log(error)
});
}
<Formik
initialValues={{ text: "" }}
onSubmit={(values) => {
if (!values.text) {
setErrorMessage("Need text");
} else {
newComment(values);
}
}}
>
<Form>
<div>
<Field
name="text"
type="contentarea"
placeholder="Text Comment"
/>
<ErrorMessage name="text" className="errorInput" />
</div>
<Button
type="submit"
title="Post comment"
aria-label="Comment"
>
Comment
</Button>
</Form>
</Formik>
Comment controller:
exports.createComment = async (req, res, next) => {
const postObject = req.body;
const UserId = req.body.UserId;
const PostId = req.body.PostId;
const firstName = req.body.firstName;
const lastName = req.body.lastName;
if (!req.body) return res.status(403).send("Veillez saisir un texte");
console.log(req.body);
console.log(UserId);
console.log(PostId);
console.log(firstName);
console.log(lastName);
const comment = new Comment({
text: req.body.text,
UserId: UserId,
PostId: PostId,
firstName: firstName,
lastName: lastName,
});
comment
.save()
.then(() => res.status(201).json({ message: "Commentaire posté" }))
.catch((error) => res.status(400).json({ error }));
};
My Back is working (tested with Postman) and I used formik for other components inside the project and it works.
I don't understand why it can't send the data in this case.
Related
When a user enters their email and password then click login a fetch request is made to my server:
const RegistrationForm = (props) => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleLoginSuccess = (props) => {
return props.history.push("./homepage");
};
const handleSubmit = (e) => {
e.preventDefault();
authApiService
.userLogin({ email, password })
.then((res) => {
password.value = "";
TokenService.saveAuthToken(res.authToken);
handleLoginSuccess();
})
.catch((res) => {
console.log(res.error);
});
};
return (
<form onSubmit={handleSubmit}>
<fieldset>
<div className="form-group">
<div>
<label htmlFor="registration-email">Email</label>
</div>
<EmailInput
value={email}
handleChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="form-group">
<div>
<label htmlFor="registration-password">Password</label>
</div>
<PasswordInput
value={password}
handleChange={(e) => setPassword(e.target.value)}
/>
</div>
</fieldset>
<Button type="submit" theme="registration-button">
Log in
</Button>
<ul>
<li>
<Link to="/register-account">Create account</Link>
</li>
</ul>
</form>
);
};
Fetch request is made here:
userLogin({ email, password }) {
return fetch(`${config.API_ENDPOINT}/auth/login`, {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({ email, password }),
})
.then((res) => {
!res.ok ? res.json().then((e) => Promise.reject(e)) : res.json();
})
.then((res) => {
TokenService.saveAuthToken(res.authToken);
IdleService.registerIdleTimerResets();
TokenService.queueCallbackBeforeExpiry(() => {
authApiService.postRefreshToken();
});
return res;
});
},
postRefreshToken() {
return fetch(`${config.API_ENDPOINT}/auth/refresh`, {
method: "POST",
headers: {
authorization: `Bearer ${TokenService.getAuthToken()}`,
},
})
.then((res) =>
!res.ok ? res.json().then((e) => Promise.reject(e)) : res.json()
)
.then((res) => {
TokenService.saveAuthToken(res.authToken);
TokenService.queueCallbackBeforeExpiry(() => {
authApiService.postRefreshToken();
});
return res;
})
.catch((err) => {
console.log("refresh token req error");
console.log(err);
});
},
Then on the server this is the route for this request:
authRouter.post("/login", jsonBodyParser, (req, res, next) => {
const { email, password } = req.body;
const userLoggingIn = { email, password };
for (const [key, value] of Object.entries(userLoggingIn))
if (value == null)
return res
.status(400)
.json({ error: `Missing '${key}' in request body` });
authService
.confirmUserNameExists(req.app.get("db"), userLoggingIn.email)
.then((userInDb) => {
if (!userInDb)
return res
.status(400)
.json({ error: "Incorrect email or password" });
});
return authService
.comparePasswords(userLoggingIn.password, userInDb.password)
.then((matchedPw) => {
if (!matchedPw)
return res
.status(400)
.json({ error: "Incorrect email or password" });
const subject = userInDb.email;
const payload = { userId: userInDb.id };
res.send({ authToken: authService.createJwt(subject, payload) });
})
.catch(next);
});
authRouter.post("/refresh", requiresAuthorization, (req, res) => {
const subject = req.user.email;
const payload = { userId: req.user.id };
res.send({
authToken: authService.createJwt(subject, payload),
});
});
Im getting the error in the title (500 error, failed to load resource and its pointing to the fetch request. I've tried googling and looking on stack overflow for hours and can't figure it out. Any help would be greatly appreciated. The goal is just to get the user logged in, redirect the user to the home page, create a JWT and store it.
I have a PUT route in the backend for liking posts, it adds the users id to the likes array in the post. This works fine when tested on Postman (by providing the post in the body) and the likes array is updated. However, when the icon is clicked in the frontend, I want the likes array to update but I'm not sure how to update the state for the post. result is showing the response in the frontend with a 200 status code but that's as far as I'm getting.
How can I update the likes array in the frontend?
Post.js
const Post = (props) => {
const [post, setPost] = useState({});
const [error, setError] = useState(false);
const id = props.match.params.id;
const loadSinglePost = (id) => {
read(id).then((data) => {
if (error) {
console.log(data.error);
setError(data.error);
} else {
setPost(data);
console.log(data);
}
});
};
useEffect(() => {
loadSinglePost(id);
}, [props]);
const like = (id) => {
const {user: { _id }, token} = isAuthenticated();
fetch(`${API}/like/${_id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
id: id,
}),
})
.then(result => { console.log(result)})
.catch((err) => {
console.log(err);
});
};
return (
<div>
<Navbar />
<div>
<h3>{post && post.title}</h3>
<p>
{post && post.author ? post.author.name : ""}
</p>
<p>{post && post.body}</p>
<h5>{post && post.likes && post.likes.length} likes</h5>
<img
onClick={() => {
like(id);
}}
alt="..."
/>
</div>
</div>
);
};
export default Post;
controllers/post.js
exports.like = (req, res) => {
Post.findByIdAndUpdate(req.body._id, {
$push: {likes: req.profile._id}
}, {new: true}).exec((err, result) => {
if (err) {
return res.status(422).json({error: err})
} else {
return res.json(result)
}
})
}
exports.readById = (req, res) => {
const id = req.params.id
Post.findById(id)
.then(post => res.json(post))
.catch(err => res.status(400).json('Error: ' + err));
}
You can update likes in post in then callback like this:
const like = (id) => {
const {user: { _id }, token} = isAuthenticated();
fetch(`${API}/like/${_id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
id: id,
}),
})
.then(result => {
// here update post likes
let updatedPost = {...post}; //to make copy of post
updatedPost.likes = [...updatedPost.likes, id]; //add new id to updatedPost' likes array
setPost(updatedPost); //update post
console.log(result)
})
.catch((err) => {
console.log(err);
});
};
Also from front-end you're sending id key in body:
body: JSON.stringify({
id: id, // here
})
And at back end you're expecting _id
Post.findByIdAndUpdate(req.body._id, { // here
$push: {likes: req.profile._id}
}
Here response data contains{name ,details} fields. I have a upload button to upload single/multi files. After uploading files, I don't refresh the page. Now for ex, I upload single file and displayed the response. Again I upload 2 files. Now I should be able to display response of current upload as well as previous one. It should be in the following format:
1.Name1
Details1
2. Name2
Details2
3. Name3
Details 3
this.state.list = this.state.list.concat(details);
this.state.list_name = this.state.list_name.concat(name);
< form onSubmit={this.handleSubmit} >
<label>
Upload a file: <br /><br />
<input type="file" name="file" multiple onChange{this.onChangeHandler}/>
</label>
<br /><br />
<button type="submit">
Upload</button>
</form >
<ol>
// {this.state.list_name.map((k) =>
// <li>{k} :</li>)}
//{this.state.list.map((k) =>
// <li>{k}</li>
// )}
</ol>
handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData();
for (var x = 0; x < this.state.selectedFile.length; x++) {
formData.append('inputFile', this.state.selectedFile[x])
fetch('url', {
method: 'POST',
body: formData
}).then(res => {
return res.json()
})
.then((res) => {
this.setState({
details: res.data.details,
name: res.data.name
})
console.log("res data", res)
//console.log("Data is", res.data.name) //displays name in the console
})
.catch(error => console.log('ERROR message'))
}
};
I have commented the code that I have tried. Thanks in advance.
you can do this
remove this
this.state.list = this.state.list.concat(details);
this.state.list_name = this.state.list_name.concat(name);
add this
fetch('url', {
method: 'POST',
body: formData
}).then(res => {
return res.json()
})
.then((res) => {
const list = this.state.list;
list.concat(res.data.details);
const list_name = this.state.list_name;
list_name.concat(name);
this.setState({
list,
list_name,
details: res.data.details,
name: res.data.name
})
console.log("res data", res)
//console.log("Data is", res.data.name) //displays name in the console
})
.catch(error => console.log('ERROR message'))
}
Trying to add new data a recipe to the table 'recipes'.
EDIT: So I have been trying out a bit,
in my index.js file where it says console.log(req.body)
I don't know if this is how it should be, but if I were to put in console.log(data) there or after the INSERT sql I get an undefined.
In my index.js (express router and more) file I logged the req.body and got a filled object, with the response I sent from my frontend Profile.js
CREATE recipe in the backend
index.js__
api.post('/recipe', passport.authenticate('jwt', {
session: false
}), (req, res) => {
const data = {
name: req.body.recipe_name,
author: req.body.recipe_author,
meal: req.body.recipe_meal,
description: req.body.recipe_description,
ingredients: req.body.recipe_ingredients,
preparation: req.body.recipe_preparation
}
console.log(req.body)
db.query('INSERT INTO recipes SET ?', data, (err, results) => {
if (err) {
res.status(500)
return;
}
db.query('SELECT * FROM recipes', (err, rows) => {
if (err) {
res.status(500)
return;
}
res.json({
recipes: rows
});
})
})
});
CREATE recipe in the frontend
Profile.js__
handleCreate(){
const jwt = localStorage.getItem('jwt')
console.log(jwt)
axios({
method: 'post',
data: {
name: this.state.name,
author: this.state.author,
meal: this.state.meal,
description: this.state.description,
ingredients: this.state.ingredients,
preparation: this.state.preparation
},
url: 'http://localhost:4000/api/recipe',
headers: {
'Authorization': 'Bearer ' + jwt
}
}).then((response) => {
this.setState({ recipe: response.data });
console.log(this)
}).catch((error, res) => {
if(error.response.status === 401) {
console.log("Error:", error);
alert("Failed")
}
})
}
Example of the input fields:
<TextField helperText="Enter the name of your recipe" label="name" onChange = {(event) => this.setState({name: event.target.value})}/>
<Button color="secondary" onClick={(event) => this.handleCreate(event)}>Submit Recipe</Button>
Problem: It is not writing it to the database
All the relevant code can be found here: https://gist.github.com/MisterSemaan/07d7cf52b0069d2ea89b29f608c2b976
I think I fixed it, by changing:::
FROM::
const data = {
name: req.body.recipe_name,
author: req.body.recipe_author,
meal: req.body.recipe_meal,
description: req.body.recipe_description,
ingredients: req.body.recipe_ingredients,
preparation: req.body.recipe_preparation
}
TO::
const data = {
recipe_name: req.body.name,
recipe_meal: req.body.meal,
recipe_author: req.body.author,
recipe_description: req.body.description,
recipe_ingredients: req.body.ingredients,
recipe_preparation: req.body.preparation
}
in index.js
Trying to add new data a recipe to the table 'recipes'.
console.log(data) and console.log(req.body) gives me the values I input and sent to the backend, but it's not writing it to the table & on Network in the chrome console I am getting a PENDING Status
CREATE recipe in the backend index.js__
api.post('/recipe', passport.authenticate('jwt', {
session: false
}), (req, res) => {
const data = {
recipe_name: req.body.name,
recipe_meal: req.body.meal,
recipe_author: req.body.author,
recipe_description: req.body.description,
recipe_ingredients: req.body.ingredients,
recipe_preparation: req.body.preparation
}
console.log(req.body)
db.query('INSERT INTO recipes SET ?', [data], (err, results) => {
console.log(data)
if (err) {
res.status(500)
return;
}
db.query('SELECT * FROM recipes', (err, rows) => {
if (err) {
res.status(500)
return;
}
res.json({
recipes: rows
});
})
})
});
CREATE recipe in the frontend Profile.js__
handleCreate(){
const jwt = localStorage.getItem('jwt')
console.log(jwt)
axios({
method: 'post',
data: {
name: this.state.name,
author: this.state.author,
meal: this.state.meal,
description: this.state.description,
ingredients: this.state.ingredients,
preparation: this.state.preparation
},
url: 'http://localhost:4000/api/recipe',
headers: {
'Authorization': 'Bearer ' + jwt
}
}).then((response) => {
this.setState({ recipe: response.data });
console.log(this)
}).catch((error, res) => {
if(error.response.status === 401) {
console.log("Error:", error);
alert("Failed")
}
})
}
Example of the input fields:
<TextField helperText="Enter the name of your recipe" label="name" onChange = {(event) => this.setState({name: event.target.value})}/>
<Button color="secondary" onClick={(event) => this.handleCreate(event)}>Submit Recipe</Button>
Yeah me again - I don't know why it was pending, but I fixed the CREATE recipe, the INSERT statement.
In api/index.js this is what the data object has to look like.
If you look into the console.log(req.user) - you notice that it's sending the id, not the user_id in the req.user -- thus we have to say that the Foreign Key user_id is the id from user.
const data = {
user_id: req.user.id,
recipe_name: req.body.name,
recipe_meal: req.body.meal,
recipe_author: req.body.author,
recipe_description: req.body.description,
recipe_ingredients: req.body.ingredients,
recipe_preparation: req.body.preparation
}
Also change this:
FROM::
db.query('SELECT * FROM recipes', (err, rows) => {
TO::
db.query('SELECT * FROM recipes WHERE user_id = ? ', [req.user.user_id], (err,
rows) => {
I also added a page reload, on success (200).
if (response.status === 200) {
console.log("Post Success");
window.location.reload();
}