POST request error: Path `title` and `body` are required - node.js

I'm trying to make a POST request to my server to create a new post (title, body) and save it in the db and I'm receiving a 200 status code however the title and body aren't being inserted into a post.
UPDATE: I have just changed return res.status(400).json({ error: errorHandler(err) }) in the controller method to res.send(err) and now I'm receiving a clear error message: The title and body paths are required.
How can I solve this?
CreatePost.js
class CreatePost extends React.Component {
constructor(props) {
super(props)
this.state = {
title: '',
body: ''
}
}
changeHandler = (e) => {
this.setState({ [e.target.name]: e.target.value })
}
submitHandler = e => {
e.preventDefault()
axios.post(`${API}/blog/post/create`, this.state)
.then(response => {
console.log(response)
}).catch(error => {
console.log(error)
})
}
render() {
const {title, body} = this.state
return (
<div>
<form onSubmit={this.submitHandler}>
<input type="text" name="title"
onChange={this.changeHandler} value={title} />
<input type="text" name="body"
onChange={this.changeHandler} value={body}/>
<button type="submit">Submit</button>
</form>
</div>
)
}
}
export default CreatePost
controllers/post.js
exports.create = (req, res) => {
let post = new Post()
post.save((err, result) => {
if(err) {
return res.status(400).json({
error: errorHandler(err)
})
}
res.json(result)
})
}
routes/posts.js
router.post('/blog/post/create', create);

Did you try to call your endpoint from Postman or Insomnia (my favorite) to verify it is up and running? This is a great method to test your endpoints independently from your code.
Since you don't use HTTP 404 in your code, I suspect it is coming from the inner mechanisms of Express.
By the way, the verb POST and the 'create' part in your API uri are stating the same intent. You could get rid of this create part. This is considered one of the best practices.

Try with this.
axios({ url: `${API}/blog/post/create`, method: 'POST', data: this.state})

I've solved the issue. I wasn't actually inserting the title and body into the post object.
I destructured title and body from req.body:
const {title, body} = req.body and inserted the data into the object let post = new Post({title, body}).
controllers/posts.js
exports.create = (req, res) => {
const {title, body} = req.body
let post = new Post({title, body})
post.save()
.then(response => {
res.send(response)
.catch(err => {
res.send(err)
})
})
}

Related

MulterError: Unexpected field error while uploading image from React js

All the answers related this error is directing towards checking the name upload.single("image") and the name attribute of the file input in client side, which is in my case same as "image" as multer. But still it is giving the error.
Following is the node js code:
const Imagestorage = multer.memoryStorage()
const upload = multer({ storage: Imagestorage })
app.post("/newpost", upload.single("image"), async(req, res) => {
console.log(req.body);
console.log(req.file);
let data={}
// convert base64 image data to string using datauri/parser, upload to cloudinary and send response
const extName = path.extname(req.file.originalname).toString();
const file64 = parser.format(extName, req.file.buffer);
const filename=file64.content
cloudinary.uploader.upload(filename, async(error, result) => {
if (error) {
res.status(500).send("error in uploading file to cloudinary"+error);
} else {
// result.secure_url is the URL of the uploaded file on Cloudinary
console.log(result.secure_url);
let Imageurl=await result.secure_url
data={
name: req.body.name,
location:req.body.location,
likes:req.body.likes,
description:req.body.description,
image:Imageurl
}
console.log(data)
let postedData=await postsModel.create(data)
res.json({
status:"ok",
postedData
})
}
});
});
//error field in case something happens with multer
// app.use((error, req, res, next) => {
// console.log('This is the rejected field ->', error.field);
// });
app.get("*", (req, res) => {
res.status(404).send("PAGE IS NOT FOUND");
})
Frontend code-
import axios from "axios";
import { useNavigate } from "react-router-dom";
const Form = () => {
const navigate = useNavigate();
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
// Append the file input to the form data
const imageFile = formData.get("image");
formData.append("image", imageFile);
// Use Axios to send a POST request to your server with the form data
axios
.post("https://instabackend-gcwk.onrender.com/newpost", formData, {
//.post("http://127.0.0.1:5000/newpost", formData, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error);
})
.finally(navigate("/insta"));
}
return (
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="image">Image:</label>
<input type="file" id="image" name="image" accept="image/*" />
<button type="submit">Submit</button>
</form>
<button onClick={() => navigate(-1)}>Go Back Home</button>
</div>
);
};
export default Form;
When i tried -
app.use((error, req, res, next) => {
console.log('This is the rejected field ->', error.field);
});
it's giving error field as "This is the rejected field -> image "
Note: There is no issue in fetching the data
Replacing append with set of FormData() is making the code work. Javascript.info explains the working of formData() here
import axios from "axios";
const App = () => {
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
//get image
const imageFile = formData.get("image");
//set image
formData.set("image", imageFile);
axios
.post("https://instabackend-gcwk.onrender.com/newpost", formData, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error);
});
}
return (
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="image">Image:</label>
<input type="file" id="image" name="image" accept="image/*" />
<button type="submit">Submit</button>
</form>
</div>
);
};
export default App;

React use axios return Axios Error {message: 'Network Error'} and TypeError: Cannot read properties of undefined (reading 'path')

when I click submit button, then web and terminal will return error like me title
but i try postman is ok , so i think is my axios setting error,how can i fixed this error? I found many similar questions, but can't not help me
the other question is , my form tag action is "/addItems", but i sending request , i got this error CANNOT POST / addItems Post http://localhost:3000/addItems 404 (Not Found)
(axios setting )
post(id, title, description, price, avatar) {
let token;
if (localStorage.getItem("user")) {
token = JSON.parse(localStorage.getItem("user")).token;
} else {
token = "";
}
const formData = new FormData();
// formData.append("id", id);
// formData.append("title", title);
// formData.append("description", description);
// formData.append("price", price);
formData.append("avatar", avatar);
return axios.post(
API_URL + "/addItems",
{ formData },
{
headers: {
Authorization: token,
"Content-Type": "multipart/form-data"
}
}
);
}
(item.route)
itemRouter.post("/addItems", upload.single("avatar"), async (req, res) => {
let { id, title, description, price, avatar } = req.body;
if (req.user.isMember()) {
return res.status(400).send("Only admin can add new items");
}
console.log(req.file);
avatar = req.file.path;
const newItem = new Item({
id,
title,
description,
price,
avatar
});
try {
await newItem.save();
console.log(req.file);
res.status(200).send("New item has been saved.");
} catch (err) {
res.status(400).send("Error");
console.log(err);
}
});
(addItemsComponent)
const handleChangePost = () => {
if (currentUser.user.role !== "admin") {
window.alert("Member can't not post item!! ");
navigate("/");
} else {
ItemService.post(avatar)
.then(() => {
window.alert("Post successfully");
navigate("/");
})
.catch((error) => {
console.log(error);
console.log(error.response);
setErrorMessage(error.response.data);
});
}
};
return (
<div>
<form action="/addItems" method="post" enctype="multipart/form-data">
<input onChange={handleChangeAvatar} value={avatar} type="file" name="avatar" />
<button type="submit" onClick={handleChangePost}>
Submit
</button>
</form>
</div>
);
Try this
return axios.post(API_URL + "/addItems", formData,
{
headers: {
Authorization: token,
"Content-Type": "multipart/form-data"
}
}
);

mern - updated values are null in data

I'm trying to update the posts. The PUT request in the back end works fine, returning 200 and updates posts when tested on Postman however when I try to update a post in the front end (react), I'm not receiving any errors but the updated post isn't being updated on submit and the updated fields (title and body) are null. The updated values are null when I console.log(data) in the front end which is why they aren't being sent to the back end but they are shown correctly in post.
Why are the updated values null inside data? How can I update the post with the new values instead of getting null?
data:
post:
Updated code: Frontend
const EditPost = ({match}) => {
const [values, setValues] = useState({
title: "",
body: "",
error: ""
});
const [post, setPost] = useState({});
const { user, token } = isAuthenticated();
const {
title,
body,
error,
} = values;
const init = (id) => {
read(id).then(data => {
if (data.error) {
setValues({...values, error: data.error})
} else {
setValues({...values,
title: data.title,
body: data.body,
})
setPost({title: values.title, body: values.body})
}
})
}
useEffect(() => {
const id = match.params.id;
init(id);
}, []);
useEffect(() => {
setPost({...values });
}, [values.title, values.body]);
const handleChange = (name) => (event) => {
setValues({ ...values, [name]: event.target.value });
};
const clickSubmit = (event) => {
event.preventDefault();
setValues({ ...values, error: "" });
editPost(match.params.userId, match.params.id, token, post).then((data) => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({
...values,
title: "",
body: "",
error: false,
});
console.log(post)
console.log(data)
}
});
};
const newPostForm = () => (
<form onSubmit={clickSubmit}>
<div>
<input
onChange={handleChange("title")} type="text"
name="title"
value={title}
/>
</div>
<div className="form-group">
<textarea
onChange={handleChange("body")}
value={body} name="body"
/>
</div>
<button type="submit">Publish</button>
</form>
);
const showError = () => (
<div
style={{ display: error ? "" : "none" }}>
{error}
</div>
);
return (
<div>
{showError()}
{newPostForm()}
</div>
);
};
export default EditPost;
export const editPost = (userId, id, token, post) => {
return fetch(`${API}/${userId}/${id}/edit`, {
method: 'PUT',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`
},
body: JSON.stringify(post)
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
};
postsByUser.js
<Link className="mypost_btn edit_btn" to={`/${_id}/${post._id}/edit`}>
Edit
</Link>
Backend code
exports.edit = (req, res) => {
if (!ObjectID.isValid(req.params.id))
return res.status(400).send(`ID is not valid: ${req.params.id}`)
const {title, body} = req.body
const updatedPost = {title, body }
Post.findByIdAndUpdate(req.params.id, {
$set: updatedPost
}, {new:true}, (error, data) => {
if (error) {
return error
} else {
res.send(data)
console.log(data)
}
})
}
Your problem lies here:
editPost(match.params.userId, match.params.id, token, post)
post is not defined.
Since post is not defined, no data is passed. Hence title and body equal to null. What you will need to do is, assuming from what I'm seeing on your code, is to define a state variable called post. I think you intended to do that:
const [post, setPost] = useState({values.title, values.body});
Then ensure that your post is updated whenever your values change using useEffect(),
useEffect(() => {
setPost({...values });
}, [values.title, value.body]);
So by the time you call your editPost() http-put-method, then post has a value. And it should work.
in EditPost.js editPost(match.params.userId, match.params.id, token).then((data) => { here you are missing the 4th arg which is the "post" it self you send to be updated

How to send data from React front-end to Nodejs Express back-end on button click

Disclaimer: I am new to React and Nodejs and have of course looked at all the current similar posts but none of them were able to help me fully so please don't mark as duplicate.
In my Nodejs index.js I have:
app.get('/list-certs', function (req, res) {
fs.readFile("certs.json", 'utf8', function (err, data) {
console.log( data );
res.send( data );
});
})
app.post('/list-certs', function (req, res) {
res.send('POST request: ' + req.body.domain-input);
console.log('post is working!')
});
And in my React App.js I have:
componentDidMount() {
this.callApi()
.then(res => {
this.setState({
json: res.map(x => x),
})
})
.catch(err => console.log(err));
}
callApi = async () => {
const response = await fetch('/list-certs');
const body = await response.json();
if (response.status !== 200) throw Error(body.message);
return body;
};
handleChange(event) {
this.setState({domainInputValue: event.target.value});
}
click() {
}
render() {
return (
<div className="App">
<form action="http://127.0.0.1:8000/list-certs" className="add-cert-form" method="post">
<h1>Add new domain</h1>
<h5 className="domain-label">Name:</h5>
<Input className="domain-input" value={this.state.domainInputValue} onChange={(e) => {this.handleChange(e)}}></Input>
<Button onClick={this.click} className="domain-button" type='primary'>Add</Button>
</form>
.
.
.
}
How do I send the data in my input field domain-input to my back-end when the button domain-button is clicked? I know something needs to go in the click() but I'm not sure what.
Any help is appreciated!
Your click function will look like it:
async click() {
const { domainInputValue } = this.state;
const request = await fetch('/echo/json', {
headers: {
'Content-type': 'application/json'
},
method: 'POST',
body: { domainInputValue }
});
}

Proxy error: Could not proxy request /users from localhost:3000 to http://localhost:3001/

I'm sending some data from my ReactJS front-end application to my node/express backend, however, whenever I send the data, I get the error message mentioned in the title.
This is my ReactJS code:
class App extends React.Component {
constructor(props) {
super(props);
//states and binding functions
}
fetchData () {
fetch('/users')
.then(res => res.json())
.then(users => this.setState({users}));
}
addUser (event) {
let fileData = new FormData();
fileData.append("file", this.state.filesToBeSent);
axios.post('adduser',
querystring.stringify({
entry: this.state.currname,
passwrd: this.state.currpasswrd,
fileData : fileData
})
)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
componentDidMount() {
this.fetchData();
}
render() {
return (
<div className="App">
<form onSubmit={this.addUser} encType="multipart/form-data">
<label>New username:</label>
<input value={this.state.currname} onChange={this.handleChange}></input>
<input value={this.state.currpasswrd} onChange={this.handlePassword} />
<input type="file" name="file" onChange={this.handleFile} />
<button type="submit" >Add</button>
</form>
<h1>Current Users: </h1>
{this.state.users.map((name, n) =>
//map through user-array and display names
)}
</ul>
</div>
);
}
}
(Sorry if it's a lot of code, I shortened it as much as possible but I wasn't sure which parts would be relevant to the question).
Here is how I receive the data in node and how I save parts of it to my db:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./uploads/");
},
filename: (req, file, cb) => {
const newFilename = `${uuidv4()}${path.extname(file.originalname)}`;
cb(null, newFilename);
},
})
const upload = multer({ storage });
router.post("/", upload.single("file"), (req, res) => {
res.send(req.file + " and exit.");
var newUser = new Todo();
newUser.username = req.body.entry;
newUser.passwrd = req.body.passwrd;
newUser.save(function (err) {
if(err)
res.send(err);
res.send('User added successfully!');
});
});
This is where it gets weird. The application works perfectly, until I insert upload.single("file"), however, I couldn't seem to figure out why. I didn't have any problems when I just had text inputs, even when I created the FormData() etc. it still worked fine until I implemented that.
I tried looking it up and to implement answers posted on here, however, nothing seems to help.
On the screen I get the following error message: Unhandled Rejection (SyntaxError): Unexpected token P in JSON at position 0
When I check the terminal I receive the error message mentioned in the title. I tried removing the content-headers (not sure what that would do, but the tutorial I was following to implement the file upload did not use content-headers, that's why I tried to remove them.
Does anyone know how to fix this error?
Edit: The error message in the terminal also contains ECONNRESET. I followed the link in the terminal https://nodejs.org/api/errors.html#errors_common_system_errors but I'm still not sure how I can fix that.
I suggest you to append all fields to FormData object, and do not convert the submitted data to json string:
let fileData = new FormData();
fileData.append("entry", this.state.currname);
fileData.append("passwrd", this.state.currpasswrd);
fileData.append("file", this.state.filesToBeSent);
axios.post('adduser', fileData)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

Resources