how to solve this Cannot POST error in MERN? - node.js

I am inserting two images along with the form data into MongoDB database.
While both images are stored in my pc folder but all form data isn't uploading in the database.
error
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /</pre>
</body>
</html>
in my console. Please help me how to solve that.
I have tried some previously asked question in stackOF.
app.js
const express = require("express")
const app = express()
const cors = require('cors');
const env = require("dotenv")
const port = 5000
env.config({path: "../server/config.env"})
require("../server/db/conn")
app.use(cors());
app.use(express.json())
app.use(require("../server/router/auth"))
app.listen(port, (err) => {
if (err) {
return console.error(err);
}
return console.log(`server is listening on ${port}`);
});
module.exports = "conn"
register.js(frontend)
const Register = () => {
const [newUser, setNewUser] = useState({
school: "",
address: "",
photo: "",
photoone: ""
});
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("school", newUser.school);
formData.append("photo", newUser.photo);
formData.append("photoone", newUser.photoone)
formData.append("address", newUser.address);
axios({
method: "post",
url: "/teacher",
data: formData,
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
console.log(response)
}).then((data) => {
console.log(data)
}).catch((error) => {
if (error.response) {
console.log(error.response.data)
}
})
};
const handleChange = (e) => {
setNewUser({ ...newUser, [e.target.name]: e.target.value });
};
const handlePhoto = (e) => {
setNewUser({ ...newUser, photo: e.target.files[0] });
};
const handlePhotoone = (e) => {
setNewUser({ ...newUser, photoone: e.target.files[0] });
};
return (
<>
<div className="container main">
<div className="row">
<div className="col-sm-6 col-md-6 col-lg-6">
<form onSubmit={handleSubmit} encType="multipart/form-data">
<div class="mb-3">
<label class="form-label">
Your school
</label>
<input
type="text"
class="form-control"
id="exampleInputPassword1"
id="school"
name="school"
value={newUser.school}
onChange={handleChange}
/>
</div>
<div class="input-group mb-3">
<input
type="file"
id="pic"
accept=".png, .jpg, .jpeg"
name="photo"
onChange={handlePhoto} type="file" class="form-control" id="inputGroupFile02" />
</div>
<div class="input-group mb-3">
<input
type="file"
id="pic"
placeholder="second photo"
accept=".png, .jpg, .jpeg"
name="photoone"
onChange={handlePhotoone} type="file" class="form-control" id="inputGroupFile01" />
</div>
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">
your address
</label>
<input
type="text"
id="address"
name="address"
value={newUser.address}
onChange={handleChange}
class="form-control"
aria-describedby="emailHelp"
/>
</div>
<button
value="register"
type="submit"
class="btn btn-primary"
>
Submit
</button>
</form>
</div>
</div>
</div>
</>
);
};
auth.js(backend)
const mongoose = require("mongoose")
const express = require("express")
const router = express()
require("../db/conn")
const User = require("../model/userSchema")
const Teacher = require("../model/userSchemaTeacher")
const multer = require('multer');
let path = require('path');
let fs = require("fs-extra");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
let schoolname = req.body.school;
let path = `C:/Users/kumar/Desktop/mern/server/images/${schoolname}`;
fs.mkdirsSync(path);
cb(null, path);
// cb(null, 'images');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
const fileFilter = (req, file, cb) => {
const allowedFileTypes = ['image/jpeg', 'image/jpg', 'image/png'];
if (allowedFileTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(null, false);
}
}
let upload = multer({ storage, fileFilter });
router.route('/teacher').post(upload.fields([{
name: "photo", maxCount: 1
}, {
name: "photoone", maxCount: 1
}
])), (req, res) => {
const school = req.body.school;
const photo = req.file.filename
const photoone = req.file.filename
const address = req.body.address;
const newUserData = {
school,
photo,
photoone,
address,
}
const newUser = new Teacher(newUserData);
newUser.save()
.then(() => res.json('User Added'))
.catch((err) => {
console.log(err);
});
}
Please see how to solve that?

The route you are trying to POST your form data is not defined please set your route path like this:
router.post('/teacher',upload.fields([{
name: "photo", maxCount: 1
}, {
name: "photoone", maxCount: 1
}
]), (req, res) => {
const school = req.body.school;
const photo = req.files['photo'][0]
const photoone = req.files['photoone'][0]
const address = req.body.address;
const newUserData = {
school,
photo,
photoone,
address,
}
const newUser = new Teacher(newUserData);
newUser.save()
.then(() => res.json('User Added'))
.catch((err) => {
console.log(err);
});
})
...

Related

Failed to send image along with other data from react to node backend

I am trying to send form data along with image from react frontend to node backend though I am getting other data but image filed is empty.Below is my code:
form.js
import React, { useState } from 'react'
const Form = () => {
const [title, setTitle] = useState("");
const [author, setAuthor] = useState("");
const [chapter, setChapter] = useState("");
const [price, setPrice] = useState("");
const [file, setFile] = useState("");
const submitData = async (e) => {
e.preventDefault();
if (file === '') {
alert('Choose file');
}
else {
const data = {
title: title,
auth: author,
chap: chapter,
cost: price,
filename: file
}
console.log(data); //Here file object showing in console
const res = await fetch('http://localhost:2000/api/addBook', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({ myData:data})
});
const res2 = await res.json();
console.log(res2);
}
}
const saveFile = (e) => {
setFile(e.target.files[0]);
};
return (
<div className='container'>
{/* <div className="contact">
<h1>Add book</h1>
</div> */}
<div className="form card">
<h1>Add book</h1>
<input type="text" className='form-control' id="title" name="title" placeholder="Title" onChange={e => setTitle(e.target.value)} />
<input type="text" className='form-control' id="author" name="author" placeholder="Author" onChange={e => setAuthor(e.target.value)} />
<input type="text" className='form-control' id="chapter" name="author" placeholder="Chapters (Separated by comma)" onChange={e => setChapter(e.target.value)} />
<input type="text" className='form-control' id="price" name="author" placeholder="Price" onChange={e => setPrice(e.target.value)} />
<input type="file" className='form-control' name="myImage" onChange={saveFile} />
<button className='btn btn-primary' type="submit" id="addData" onClick={submitData}>ADD</button>
</div>
</div>
react)
}
export default Form;
backend
const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
app.use(fileUpload());
const addBook = async (req, res) => {
const { myData } = req.body;
// const file = req.files.profileImg; //Its showing error when I am using profileImg not found
console.log(myData);
}
module.exports = { addBook };
In backend terminal I am getting below output where filename object is empty:
{
title: 'nancy drew',
auth: 'unknown',
chap: 'First',
cost: '200',
filename: {}
}
How can I get file on backend side someone let me know.

Multer not able to get the filename

I'm not able to get the filename or path from Multer. This is what I've done so far:
uploadcsv.js
const fileUpload = multer({
limits: 500000,
storage:multer.diskStorage({
destination: (req, file, cb) =>{
cb(null,'upload/csv')
},
filename: (req, file, cb) =>{
const ext = MIME_TYPE_MAP[file.mimetype]
cb(null, uuid + '.' + ext)
},
fileFilter: (req, file, cb) =>{
const isValid = !!MIME_TYPE_MAP[file.mimetype]
let error = isValid ? null : new Error('Invalid mime type')
cb(error, isValid)
}
})
})
Then the route api:
router.post('/contact/importcontact', JWTAuthenticationToken, fileUpload.single('csv'), async (req, res) => {
console.log(req.body)
console.log(req.file.filename)
const csvFilePath = req.file.filename
const stream = fs.createReadStream(csvfile);
const account= await Account.findOne({ acctid: { "$eq": req.body.acctid } })
try {
if (req.file == undefined)
return res.status(400).send({ msg: 'No files were uploaded.' });
csvtojson()
.fromFile(csvFilePath)
.then((jsonObj) => {
console.log(jsonObj);
})
// Async / await usage
const jsonArray = await csvtojson().fromFile(csvFilePath);
res.json({ success: "Uploaded Successfully", status: 200 })
} catch (error) {
res.json({ message: error })
}
})
Lastly, the react importcustomer.js
const handleCSVChange = (e) => {
console.log(e.target.files[0])
setCsvData(e.target.files[0])
setUploadButtonData(e.target.files[0].name)
}
const uploadCSVData = async (e) => {
setLoading(true)
const formData = new FormData();
formData.append("csv", csvData);
console.log(formData)
e.preventDefault()
const response = await Axios.post(process.env.REACT_APP_FETCH_URL + '/api/contact/importcontact', { formData: formData, acctid: lsData.acctid}, { withCredentials: true })
if (response.data.statusCode === "409") {
setMessage(response.data.msg)
setLoading(false)
}
else if (response.data.statusCode === "200") {
setLoading(false)
//history.push('/sources')
}
}
return (
<div className="col-12 grid-margin stretch-card">
<div className="card">
<div className="card-body">
<h4 className="card-title">Import Customer Data From CSV</h4>
<form className="forms-sample" enctype="multipart/form-data">
<div className="form-group">
<label for="files" className="btn btn-primary">{uploadButtonData}
<input id="files" type="file" name="csv" className="form-control" hidden accept="*.csv" onChange={handleCSVChange} /></label>
</div>
<button className="btn btn-primary" onClick={uploadCSVData} style={{ float: "right", width: "7rem" }} type="button">
{loading && <i className="fa fa-refresh fa-spin"></i>}
Upload CSV</button>
<div className="mt-3" style={{ textAlign: "center" }}>
<span id="msg" style={{ color: "red" }}>{message}</span>
</div>
</form>
</div>
</div>
</div>
)
Though I'm able to console.log(req.body) and console.log(e.target.files[0]) and getting the acctid and filename but returned empty for the console.log(formData) and console.log(req.file.filename) returned undefined. What have I missed? Many thanks in advance and greatly appreciate any helps. Thanks again
I have managed to solves this by appending the acctid to formData:
const formData = new FormData();
formData.append("csv", csvData);
formData.append("accctid", lsData.acctid);
const response = await Axios.post(process.env.REACT_APP_FETCH_URL + '/api/contact/importcontact', formData, { withCredentials: true })

req.file is showing undefined in console

I am trying to upload a video on youtube from my web app but I am getting an error in sending a file to my backend it is showing the req.file as undefined in req.body it is showing videoFile: "Undefined" and all other values I can see but I am not able to get the file from my react app to backend .
Input.jsx
import axios from "axios";
import React, { useState } from "react";
// import Axios from "axios";
function Input() {
const [form, setForm] = useState({
title: "",
description: "",
file: null,
});
function handleChange(event) {
const InputValue =
event.target.name === "file" ? event.target.file : event.target.value;
setForm({
...form,
[event.target.name]: InputValue,
});
}
function handleSubmit(event) {
event.preventDefault();
console.log({ form });
const headers = {
"content-type": "multipart/form-data",
};
const videoData = new FormData();
videoData.append("videoFile", form.file);
videoData.append("title", form.title);
videoData.append("description", form.description);
axios
.post("http://localhost:3001/upload", videoData, { headers })
.then((res) => {
console.log(res.data);
})
.catch((err) => console.log(err));
}
return (
<div className="form">
<h1>
<i className="fab fa-youtube"></i> Upload video
</h1>
<form onSubmit={handleSubmit} method="POST" enctype="multipart/form-data">
<div>
<input
className="title"
type="text"
placeholder="Title"
name="title"
autoComplete="off"
onChange={handleChange}
/>
</div>
<div>
<textarea
typeof="text"
placeholder="description"
name="description"
autoComplete="off"
onChange={handleChange}
/>
</div>
<div>
<input
type="file"
accept="video/mp4,video/x-m4v,video/*"
placeholder="Add"
name="file"
onChange={handleChange}
/>
</div>
<button className="btn btn-light" type="submit">
Upload Video
</button>
</form>
</div>
);
}
export default Input;
it is node.js part
App.js (backend)
const express = require("express");
const multer = require("multer");
const youtube = require("youtube-api");
const open = require("open");
const cors = require("cors");
const fs = require("fs");
const credentials = require("./client_secret_1013548512515-lti2tpl88m8qqkum1hh095cnevtdi3lu.apps.googleusercontent.com.json");
const app = express();
const bodyParser = require("body-parser");
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
const storage = multer.diskStorage({
destination: "./",
filename: (req, file, cb) => {
const newFileName = `${Date.now()}-${file.originalname}`;
cb(null, newFileName);
},
});
const uploadVideoFile = multer({
storage: storage,
}).single("videoFile");
app.post("/upload", uploadVideoFile, (req, res) => {
console.log(req.body);
console.log(req.file); //it is showing undefined
if (req.file) { //getting error in this part
const filename = req.file.filename;
const { title, description } = req.body;
open(
oAuth.generateAuthUrl({
access_type: "offline",
scope: "https://www.googleapis.com/auth/youtube.upload",
state: JSON.stringify({
filename,
title,
description,
}),
})
);
}
});
app.get("/oauth2callback", (req, res) => {
res.redirect("http://localhost:3000/success");
const { filename, title, description } = JSON.parse(req.query.state);
oAuth.getToken(req.query.code, (err, tokens) => {
if (err) {
console.log(err);
return;
}
oAuth.setCredentials(tokens);
youtube.videos.insert(
{
resource: {
snippet: { title, description },
status: { privacyStatus: "private" },
},
part: "snippet,status",
media: {
body: fs.createReadStream(filename),
},
},
(err, data) => {
console.log("Done");
process.exit();
}
);
});
});
const oAuth = youtube.authenticate({
type: "oauth",
client_id: credentials.web.client_id,
client_secret: credentials.web.client_secret,
redirect_url: credentials.web.redirect_uris[0],
});
PORT = 3001;
app.listen(PORT, () => {
console.log("app is listening on port 3001");
});
Please make the following changes in the Input.jsx file.
// 1. Inside the handleChange() function
const InputValue = event.target.name === "file" ? event.target.files : event.target.value;
// 2. Inside the handleSubmit() function
videoData.append("videoFile", form.file[0], form.file[0].name);
This should output the file object inside req.file.

Upload image with Multer and Formik to Mongodb (MERN)

I created app using MERN.
Now I'm trying to upload image with Multer and Formik, but req.file returns undefined, and I can't understand why.
I'm new in this, but I guess this may cause from JSON.stringify (http.hook) or content-type: application/json. I also tried do this with FormData, but that's not working. Any ideas?
UPDATE: With Postman works good. I think problem is in ui part, input doesn,t pass the file.
app.js
const {Router} = require('express');
const multer = require('multer');
const auth = require('../middleware/auth.middleware');
const Users= require('../models/Users');
const router = Router();
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './client/public/uploads/');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const upload = multer({
storage: storage,
limits: { fileSize: 10 * 1024 * 1024 }
});
router.post('/create', upload.single('image'), auth, async (req, res) => {
console.log(req.file);
try {
const code = req.body.code;
const existing = await Users.findOne({code: code});
if(existing) {
return res.json({user: existing})
}
const user = new Users(req.body);
await user .save();
res.status(201).json(user);
} catch (e) {
console.log(e);
res.status(500).json({ message: 'Error: try again.' })
}
});
http.hook.js
import {useState, useCallback} from 'react';
export const useHttp = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const request = useCallback(async (url, method = 'GET', body = null, headers = {}) => {
setLoading(true);
try {
if(body) {
body = JSON.stringify(body);
headers['Content-Type'] = 'application/json';
}
const response = await fetch(url, {method, body, headers});
const data = await response.json();
if(!response.ok) {
throw new Error(data.message || 'Something goes wrong')
}
setTimeout(() => {
setLoading(false);
}, 800);
return data
} catch (e) {
setLoading(false);
setError(e.message);
throw e;
}
}, []);
const clearError = useCallback(() => {setError(null)}, []);
return {loading, request, error, clearError}};
CreateUser.js
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {useHttp} from "../hooks/http.hook";
import Button from "../components/Button/Button";
import {AuthContext} from "../context/auth.context";
import {Formik} from "formik";
export const CreateUser = () => {
const {token} = useContext(AuthContext);
const {loading, request} = useHttp();
const createUser = useCallback(async (body) => {
try {
const fetched = await request(`/api/user/create`, 'POST', body, {
Authorization: `Bearer ${token}`
});
} catch (e) {console.log(e)}
}, []);
const handleCreate = (values, {resetForm}) => {
console.log(values);
createUser(values);
// resetForm({});
};
return (
<div className="wrapper">
<div className="row">
<div className="column small-12 text-center color-white mb_45">
<div className="custom-headline text text-48 font-bold">
<h1>
Crate user
</h1>
</div>
</div>
</div>
<Formik
enableReinitialize
initialValues={{
name: '',
code: '',,
image: null
}}
onSubmit={handleCreate}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
isSubmitting,
setFieldValue,
resetForm
}) => (
<form onSubmit={handleSubmit} className="row align-center">
<div className="column small-12 large-7">
<div className="form-item flex-container align-middle mb_20">
<label className="text text-14 font-semibold font-uppercase text-right small-4">
Photos
</label>
<input id="image" type="file" name="image" className="file_input"
onChange={(event) => {
setFieldValue("image", event.currentTarget.files[0]);
}} />
</div>
</div>
<div className="column small-12 large-7">
<div className="form-item flex-container align-middle mb_20">
<label className="text text-14 font-semibold font-uppercase text-right small-4">
Name
</label>
<input
className="text text-17 "
type="text"
name="name"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
</div>
</div>
<div className="column small-12 large-7">
<div className="form-item flex-container align-middle mb_20">
<label className="text text-14 font-semibold font-uppercase text-right small-4">
Code
</label>
<input
className="text text-17"
type="text"
name="code"
onChange={handleChange}
onBlur={handleBlur}
value={values.code}
/>
</div>
</div>
<div className="column small-12 mt_20">
<div className="btn_group flex-container flex-wrap align-middle align-center">
<Button className="btn-lg radius-8" theme="blue"
text={Submit} type="submit"
/>
</div>
</div>
</form>
)}
</Formik>
</div>
)
};
Wrap out your image file with formData with the multer key "image"
upload.single('image')
on Front-End
const handleCreate = async (values) => {
try {
const body = new FormData();
body.append( "image", values.image);
...
} catch (err) {}
};
And make sure about your destination path use "dirname"
`${__dirname}/../client/public/uploads/`
Change this according to your directory path
OK! I don't know WHY this was cause, but I found solution - I use axios instead of fetch, and of course FormData for uploading images or files, and it works!
Hope this may be helpful for someone else. Thanks for all answers.
const handleCreate = (values, {resetForm}) => {
const formData = new FormData();
formData.append('name', values.name);
formData.append('code', values.code);
formData.append('image', values.image);
axios.post('/api/user/create', formData)
.then(console.log)
catch(console.error);
resetForm({});
};
I have 2-3 suggestion,
in your app.js file
router.post('/create', upload.single('image'), auth, async (req, res) => {
console.log(req.file);
you should use auth middelware before using upload.single.
and you should send headers with POST request with {content type: multipart/form-data}

POST http://localhost:5000/books/add 400 (Bad Request)

I am creating a Book store app using MERN. But when I am trying to upload a new book, it is returning 'POST http://localhost:5000/books/add 400 (Bad Request)'.
Not sure why it is happening, In this case, the book is not gating uploaded but the cover image is gatting store in/ uploads dir. But data is not going to the mongoose.
Using multer to upload bookcover and react with hooks
.
Please Help, Here is the code
backend\routes\Books.js
const router = require("express").Router();
let Book = require("../models/BookModel");
const multer = require('multer');
const storage = multer.diskStorage({
destination:function(req, file, cb){
cb(null, './uploads/');
},
filename:function(req, file, cb){
cb(null, file.originalname);
}
});
const fileFIlter = (req, file,cb) => {
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/png'){
cb(null, true);
}
else{
cb(null, false);
}
}
const upload = multer({storage:storage, limits:{
fileSize: 1024 * 1024 * 2
}});
router.route("/").get((req, res) => {
Book.find()
.then((books) => res.json(books))
.catch((err) => res.status(400).json("Error: " + err));
});
router.route("/add").post(upload.single('cover'), (req, res) => {
console.log(req.file);
const name = req.body.name;
const author = req.body.author;
const price = req.body.price;
const summary = req.body.summary;
const cover = req.file.path;
const newBook = new Book({
name,
author,
price,
summary,
cover
});
newBook
.save()
.then(() => res.json("Book Added!"))
.catch((err) => res.status(400).json("Error: " + err));
});
router.route("/:id").get((req, res) => {
Book.findById(req.params.id)
.then((book) => res.json(book))
.catch((err) => res.status(400).json("Error: " + err));
});
router.route("/:id").delete((req, res) => {
Book.findByIdAndDelete(req.params.id)
.then(() => res.json("Book Deleted!"))
.catch((err) => res.status(400).json("Error: " + err));
});
router.route("/update/:id").post(upload.single('cover'),(req, res) => {
Book.findById(req.params.id)
.then((book) => {
book.name = req.body.name;
book.author = req.body.author;
book.price = req.body.price;
book.summary = req.body.summary;
book.cover = req.file.path;
book
.save()
.then(() => res.json("Book Updated!"))
.catch((err) => res.status(400).json("Error: " + err));
})
.catch((err) => res.status(400).json("Error: " + err));
});
module.exports = router;
and frontend\src\pages\AddBookPage.js
import {useState} from "react";
import axios from "axios";
const AddBookPage = () => {
const [Book, SetBook] = useState({
name:"",
author:"",
price:"",
summary:"",
cover:null
});
// Handel Input Change
const handleChange = (e) => {
SetBook({...Book,
[e.target.name]: e.target.value,
});
};
// Handel Input Change
const handleFileChange = (e) => {
SetBook({...Book,
[e.target.name]: e.target.files[0],
});
console.log(Book.cover)
};
// Update book to server
const handleSubmit = (e) => {
e.preventDefault();
console.log(Book.cover);
const formData = new FormData();
formData.append(
'cover',
Book.cover
);
const config = {
headers: {
'content-type': 'multipart/form-data'
}
};
const book = {
name:Book.name,
author:Book.author,
price:Book.price,
summary:Book.summary,
cover:Book.cover.name
};
axios
.post(
`http://localhost:5000/books/add`, formData, config, book
)
.then((res) => console.log(res.data))
.catch((err) => console.log(err));
console.log(book);
};
return (
<main>
<div className="book_page book_edit_page">
<div className="book_edit_warp">
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="name">Name</label>
<input
type="text"
className="form-control"
id="name"
name="name"
required
onChange={handleChange}
value={Book.name}
/>
</div>
<div className="form-group">
<label htmlFor="author">Author</label>
<input
type="text"
className="form-control"
id="author"
name="author"
required
onChange={handleChange}
value={Book.author}
/>
</div>
<div className="form-group">
<label htmlFor="price">Price</label>
<input
type="text"
className="form-control"
id="price"
name="price"
required
onChange={handleChange}
value={Book.price}
/>
</div>
<div className="form-group">
<label htmlFor="summary">Summary</label>
<textarea
type="text"
className="form-control"
id="summary"
name="summary"
required
onChange={handleChange}
value={Book.summary}
/>
</div>
<div className="form-group">
<label htmlFor="cover">Book Cover</label>
<input
type="file"
className="form-control"
id="cover"
name="cover"
required
onChange={handleFileChange}
/>
</div>
<button type="submit" className="btn btn-primary">
Update
</button>
</form>
</div>
</div>
</main>
)
}
export default AddBookPage;

Resources