Having Trouble posting data to api in react - node.js

I am following a mern stack tutorial and trying to send data to api from react js form which is:
import axios from 'axios'
import { useState } from 'react'
import './share.css'
export default function Share() {
const [username, setUsername] = useState('')
const [file, setFile] = useState(null)
const handleSubmit = async(e)=>{
e.preventDefault()
const newPost = {
username: username
}
if(file){
const data = new FormData()
const fileName = file.name
data.append('name', fileName)
data.append('file', file)
newPost.pic = fileName
console.log(newPost)
try{
await axios.post('http://localhost:5000/upload', data)
}catch(err){
console.log(err)
}
}
try{
await axios.post('http://localhost:5000/post/post', newPost)
}catch(err){
console.log(err)
}
}
return (
<form className='share' onSubmit={handleSubmit}>
<div className='shareTop'>
<span>M</span>
<input className='shareInput' type='text' placeholder="What's happening?" onChange={(e)=>setUsername(e.target.value) } />
</div>
<div className='shareBottom'>
<div className='bottomIcons'>
<label htmlFor='file'>
<i class="fa-solid fa-face-meh"></i>
<input type='file' style={{display:"none"}} name='file' id='file' onChange={(e)=>setFile(e.target.files[0])} />
</label>
<i class="fa-solid fa-calendar"></i>
<i class="fa-solid fa-notes"></i>
<i class="fa-solid fa-bookmark"></i>
</div>
<button type='submit'>Tweet</button>
</div>
</form>
)
}
and my index js (serve side) file is:
const express = require('express')
const app = express()
const mongoose = require('mongoose')
const helmet = require('helmet')
const morgan = require('morgan')
const postRoute = require('./routes/posts')
const multer = require('multer')
const bodyParser = require('body-parser')
const cors = require('cors')
app.use(cors())
app.use(express.json())
app.use(morgan('common'))
app.use(helmet())
app.use(express.static('uploads'))
const storage = multer.diskStorage({
destination: function(req, file, cb){
cb(null, './uploads')
},
filename: function(req, file, cb){
cb(null, req.body.name)
}
})
const upload = multer({storage});
app.post('/upload', upload.single('file'), (req, res)=>{
})
app.use('/post/', postRoute)
mongoose.connect('mongodb://localhost:27017/twitter').then(()=>{
console.log("Connected to Database")
})
app.listen(5000, ()=>{
console.log('Listening')
})
and posts route is:
const express = require('express')
const router = express.Router()
const Post = require('../models/Post')
router.post('/post', async(req, res)=>{
const post = new Post({
username: req.body.username,
pic: req.body.pic
})
try{
const newPost = await post.save()
console.log("post has been saved")
res.status(200).json("Post has been saved")
}catch(err){
res.status(500).json(err)
}
})
router.put('/:id', async(req, res)=>{
const post =await Post.findByIdAndUpdate(req.params.id, {$set:req.body})
res.status(200).json("Account has been updated")
})
router.get('/', async (req, res)=>{
const posts = await Post.find()
res.status(200).json(posts)
})
router.delete('/', async(req, res)=>{
await Post.deleteMany()
})
module.exports = router
So the problem is that the file is being uploaded to backend but the data does not, after doing some research i realized that the second try and catch block where i am posting the content is not being called, just the first api where we upload file is being called, can someone tell me what am i doing?

Related

React Nodejs Express Server Cannot GET

I'm developing my first full-stack project. I developed the client side and server side. You can see the code down. When I run the client (Front end side ) it is working in localhost. Then when I ran the backend side I got a 'Cannot GET' message. Any idea about this?
Index.js
const express = require("express");
const app = express();
const dotenv = require("dotenv");
const mongoose = require("mongoose");
const authRoute = require("./routes/auth");
const userRoute = require("./routes/users");
const postRoute = require("./routes/posts");
const categoryRoute = require("./routes/categories");
const multer = require("multer");
const path = require("path");
dotenv.config();
app.use(express.json());
app.use("/images", express.static(path.join(__dirname, "/images")));
mongoose.connect(process.env.MONGO_URL).then(console.log('Connected to mongo')).catch(err=>console.log(err));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "images");
},
filename: (req, file, cb) => {
cb(null, req.body.name);
},
});
const upload = multer({ storage: storage });
app.post("/api/upload", upload.single("file"), (req, res) => {
res.status(200).json("File has been uploaded");
});
app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.use("/api/posts", postRoute);
app.use("/api/categories", categoryRoute);
app.listen("3000", () => {
console.log("Backend is running.");
});
Home.jsx
import React from 'react'
import Header from '../../components/header/Header'
import Posts from '../../components/posts/Posts'
import Sidebar from '../../components/sidebar/Sidebar'
import axios from "axios";
import { useEffect, useState } from "react";
export default function Home() {
const [posts, setPosts] = useState([]);
useEffect(() => {
const fetchPosts = async () => {
const res = await axios.get("/posts");
console.log(res)
setPosts(res.data);
};
fetchPosts();
});
return (
<>
<div className="mt-8">
<Header/>
</div>
<div className="container">
<div className="row mt-5">
<div className="col-lg-4 col-md-4">
<Posts posts={posts}/>
</div>
<div className="col-lg-4 col-md-4 ms-auto">
<Sidebar/>
</div>
</div>
</div>
</>
)
}
I added proxy to package.json file. (Client side).
"proxy": "http://localhost:3000/api/",

File uploading with Express: req.files is undefined

I am making a pinterest clone so I need to upload images but I cant fetch files from frontend to back end(with axios)
this is the server
I tested so many stuff but I can't understand where is the flaw. The app stores the photo and it seems that the problem happens when I want to get the data to backend but only files cuz I can fetch string from frontend
const express = require('express');
const app = express()
const mongoose = require('mongoose')
const cors = require('cors')
const Photo = require('./models/Photo')
const multer = require('multer')
//MiddleWare
app.use(cors())
app.use(express.json())
mongoose.connect('', () =>{
console.log('Connected to DB..')
})
// storage
const Storage = multer.diskStorage({
destination: 'uploads',
filename: (req, file,cb) =>{
cb(null, file.originalname)
}
})
const upload = multer({
storage: Storage,
}).single('testImage')
app.post('/add', async(req, res) =>{
console.log(req.files)
})
app.listen(3001, () =>{
console.log('Listening..')
})
And this is client side
/* eslint-disable jsx-a11y/alt-text */
/* eslint-disable react/jsx-no-comment-textnodes */
import React, { useState, useRef } from "react";
import NotificationsIcon from "#mui/icons-material/Notifications";
import AddAPhotoIcon from "#mui/icons-material/AddAPhoto";
import "./Header.css";
import axios from "axios"
const Header = ({gallery, setGallery}) => {
const [open, setOpen] = useState(false);
const [photo, setPhoto] = useState('')
const handleModel = (e) => {
setOpen(!open);
};
const handlePhoto = (e) => {
setPhoto(e.target.files[0])
}
const handleSubmit = e=>{
e.preventDefault();
setOpen(!open);
console.log(photo)
axios.post('http://localhost:3001/add',{photo: photo})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
}
return (
<div className="header">
<div className="nav">
<img
src="https://i.pinimg.com/originals/0d/ea/4a/0dea4ad3030467e2f65cde00935ba62b.png"
className="logo"
/>
<input type="text" className="search-input" placeholder="Search" />
<NotificationsIcon color="action" fontSize="large" className="icon" />
<AddAPhotoIcon
color="action"
fontSize="large"
className="add-icon icon"
onClick={handleModel}
/>
</div>
{open ? (
<form onSubmit={handleSubmit} className="popup" encType='multipart/form-data'>
<input
type="file"
accept=".png, .jpg, .jpeg"
filename='testImage'
onChange={handlePhoto}
/>
<button >Submit</button>
</form>
) : (
""
)}
</div>
);
};
export default Header;
Server console logs undefined when I upload an image but why tho??
Multer returns you a middleware when you invoke the multer() function.
so in your case you should add the middleware to your route.
const upload = multer({
storage: Storage,
}).single('testImage');
app.post('/add', upload ,async(req, res) =>{
console.log(req.file)
})
Now your route '/add' will look for the key testImage in the multipart/form-data.
You need to pass the upload as formData
const formData = new FormData();
formData.append('files', photo); //this matches req.files
const res = await axios.post('http://localhost:3001/add', formData, {
headers: formData.getHeaders() //formData will set content-type etc
});
and update route to use middleware
app.post('/add', upload, async(req, res) => {})

Uploading Images using Multer (works locally, but not when deployed on Heroku)

I'm a bit stuck with my blog app.
It works properly when I run it locally, but when it's deployed to Heroku it seems that the images that get uploaded via Multer aren't being uploaded into my images folder
When I create a post from the Heroku app, I can create the post - but the picture is missing
Below is my server code
const path = require("path");
const db = require('./config/connection');
const multer = require('multer')
const routes = require('./routes');
const app = express()
const PORT = process.env.PORT || 5000
app.use(express.urlencoded({ extended: true }));
app.use(express.json())
app.use("/images", express.static(path.join(__dirname, "./images")));
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, 'images')
},
filename: (req, file, callback) => {
callback(null, req.body.name)
}
})
const upload = multer({ storage: storage })
app.post('/upload', upload.single('file'), (req, res) => {
res.status(200).json('File has been uploaded')
})
if (process.env.NODE_ENV === 'production') {
app.use(express.static("client/build"));
}
app.use(routes)
db.once('open', () => {
app.listen(PORT, () => {
console.log(`API server running on port ${PORT}!`);
});
});
Below here is my client code
import React, { useContext, useState } from 'react';
import './write.css';
import { Context } from '../../context/Context';
export default function Write() {
const [title, setTitle] = useState('')
const [description, setDescription] = useState('')
const [file, setFile] = useState('')
const { user } = useContext(Context)
const handleSubmit = async (e) => {
e.preventDefault()
const newPost = {
username: user.username,
title,
description,
}
if(file){
const data = new FormData()
const filename = Date.now() + file.name
data.append('name', filename)
data.append('file', file)
newPost.postPicture = filename
try {
await axios.post('/upload', data)
} catch (error) {
console.log(error)
}
}
try {
const response = await axios.post('/posts', newPost)
window.location.replace('/posts/'+response.data._id)
} catch (error) {
console.log(error)
}
}
return (
<div className='write'>
{file &&
<img
className='write_image'
src={URL.createObjectURL(file)}
alt=""
/>
}
<form className='write_form' onSubmit={handleSubmit}>
<div className='write_form_group'>
<label htmlFor='file_input'>
<i className='write_icon far fa-plus-square'></i>
</label>
<input type='file' id='file_input' style={{display: 'none'}} onChange={e=>setFile(e.target.files[0])} />
<input type='text' placeholder='Title' className='write_input' onChange={e=>setTitle(e.target.value)}/>
</div>
<div className="write_form_group">
<textarea placeholder='Tell your story...' type='text' className='write_input write_text' onChange={e=>setDescription(e.target.value)}></textarea>
</div>
<button className='write_submit' type='submit'>Publish</button>
</form>
</div>
)
}
I'm not sure what's going wrong, my brain is being pointed into the server side code where I use multer.diskStorage (maybe this doesn't work when the app is being hosted somewhere?)
Any advice would be amazing
Also here is the link to the whole repo on my github... because I feel like just looking at the code in these posts might be hard to follow
https://github.com/Wickette/wickettes_blog
Heroku doesn't let you do this. You need to create a bucket on Amazon's S3 service or another similar service to upload that.
You may also use cloudinary its easy to use also a free service.

Axios Error: Request failed with status code 404

first of all I had a project that i needed to send an image to AWS S3 bucket .. so I need first to send image from front end to back end so i used Axios to do that.. but now i needed to copy this code in my new application so i tested my old application first and it successfully worked .. but when i created that new application it shows me that error.
enter image description here
sounds like the route i am giving it wrong but i checked alot of times its not wrong at all
here is my frontend code
import { useState } from 'react'
import axios from 'axios'
async function postImage({image, description}) {
const formData = new FormData();
formData.append("image", image)
formData.append("description", description)
const result = await axios.post('/images', formData, { headers: {'Content-Type': 'multipart/form-data'}})
.catch(function (error) {
console.log(error);
});
return result.data
}
function Image() {
const [file, setFile] = useState()
const [description, setDescription] = useState("")
const [images, setImages] = useState([])
const submit = async event => {
event.preventDefault()
const result = await postImage({image: file, description})
setImages([result.image, ...images])
}
const fileSelected = event => {
const file = event.target.files[0]
setFile(file)
}
return (
<div className="App">
<form onSubmit={submit}>
<input onChange={fileSelected} type="file" accept="image/*"></input>
<input value={description} onChange={e => setDescription(e.target.value)} type="text"></input>
<button type="submit">Submit</button>
</form>
</div>
);
}
export default Image;
the error that i am catching is
Error: Request failed with status code 404
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:62)
here is my backend code
const express = require("express");
const fs = require("fs");
const util = require("util");
// const unlinkFile = util.promisify(fs.unlink);
const path = require("path");
const multer = require("multer");
const upload = multer({ dest: "uploads/" });
// const { uploadFile, getFileStream } = require("./s3");
const app = express();
app.post('/images', upload.single('image'), async (req, res) => {
// const file = req.file
console.log(file)
})
const port = process.env.PORT || 5000;
app.listen(port);
console.log("App is listening on port " + port);

MERN Stack: POSTing data to database with Express/React

I'm new to the MERN stack and backend programming. I have a React form that I want to submit to an MLab database using Express. I am unable to successfully POST the form data to the database. I'm not sure if I'm taking the correct approach or not. My form is working and I am able to log the fields, I run into problems when trying to do a POST request to submit the form data.
Here is my form:
import React from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Label, Input } from 'reactstrap';
class AddBookModal extends React.Component {
constructor(props) {
super(props);
this.state = {
modal: false,
bookTitle: '',
author: '',
genre: ''
};
this.toggle = this.toggle.bind(this);
this.onSubmit = this.handleSubmit.bind(this);
}
toggle() {
this.setState(prevState => ({
modal: !prevState.modal
}));
}
handleSubmit = (event) => {
event.preventDefault();
const data = this.state;
//console.log("Data from form :" + data.bookTitle, data.author, data.genre);
}
handleInputChange = (event) => {
event.preventDefault();
this.setState({
[event.target.name]:
event.target.value
});
}
render() {
const {bookTitle} = this.state;
const {author} = this.state;
const {genre} = this.state;
return (
<div>
<Button id="add-book-button" onClick={this.toggle}>Add Book</Button>
<Modal isOpen={this.state.modal} toggle={this.toggle} className={this.props.className}>
<ModalHeader toggle={this.toggle}>Add Book</ModalHeader>
<ModalBody>
<Form method="POST" action="/profile" id="add-book-form" onSubmit={this.handleSubmit} >
<FormGroup>
<Label for="book-title-label">Book Title</Label>
<Input
value={bookTitle}
name="bookTitle"
onChange={this.handleInputChange}
placeholder="Enter name of book" />
</FormGroup>
<FormGroup>
<Label for="book-author-label">Author</Label>
<Input
value={author}
name="author"
onChange={this.handleInputChange}
placeholder="Enter author of book" />
</FormGroup>
<FormGroup>
<Label for="exampleSelect">Genre</Label>
<Input
onChange={this.handleInputChange}
value={genre}
type="select"
name="genre"
id="exampleSelect">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</Input>
</FormGroup>
<ModalFooter>
<Button color="primary" type="submit" onClick={this.toggle}>Submit</Button>{' '}
<Button color="secondary" onClick={this.toggle}>Cancel</Button>
</ModalFooter>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
export default AddBookModal;
Here is my Express route:
const router = require('express').Router();
const bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
// localhost:3000/profile
// User Model
const User = require('../../models/user-model');
const Book = require('../../models/book-model');
// Checks if user is not logged in
const authCheck = (req, res, next) => {
if(!req.user) {
// If user is not logged in, redirect them to login page
res.redirect('/auth/login');
}
else {
// If user is logged in call next in router.get
next();
}
};
router.get('/', authCheck, (req, res) => {
res.send('you are logged in, this is your profile : ' + req.user);
});
router.post('/', urlencodedParser, (req, res) => {
console.log(req.body);
const newUser = new User({
name: req.body.name,
username: req.body.username,
githubID: req.body.githubID,
profileUrl: req.body.profileUrl,
avatar: req.body.avatar,
books: {
bookTitle: req.body.bookTitle,
author: req.body.author,
genre: req.body.genre
}
});
newUser.save()
.then(data => {
res.json(data)
})
.catch(err => {
res.send("Error posting to DB")
});
});
module.exports = router;
Here is my Express server:
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const authRoutes = require('./routes/api/auth');
const passportSetup = require('./config/passport-setup');
const cookieSession = require('cookie-session');
const keys = require('./config/keys');
const passport = require('passport');
const profileRoutes = require('./routes/api/profile-routes');
const bookRoutes = require('./routes/api/book-routes');
// Hooks up routes/api/items file
const items = require('./routes/api/items');
const app = express();
// Boderparser Middleware
app.use(bodyParser.json());
// sets up session cookies
app.use(cookieSession({
// Max age set to 1 day
maxAge: 24 * 60 * 60 * 1000,
// Uses cookieKey from keys file to encrypt
keys: [keys.session.cookieKey]
}));
// initialize passport
app.use(passport.initialize());
app.use(passport.session());
// DB Config
const db = require('./config/keys').mongoURI;
// Connect to mongodb
mongoose
.connect(db, { useNewUrlParser: true })
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
// Use Routes, sets up routes/api/items to be used
app.use('/api/items', items);
app.use('/book', bookRoutes);
// Use auth.js's routes
app.use('/auth', authRoutes);
// Use profile-routes routes for profile page
app.use('/profile', profileRoutes);
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`))
I'm unable to make a POST request and not sure why. The Express route handles some OAuth stuff and displays the logged in user's profile. On that same page I have the form which allows the user to add data and submit it. Is the logic from authCheck interfering with POSTing the form data? The router.post in my Express route does not successfully console.log anything.
I've seen people use Axios in the React form component itself to do a POST request. Is it better to do form POST requests with Axios or should I be handling it in the Express route?
You should use the axios for making the api call.
In your handleSubmit function you are using "event.preventDefault()" which will prevent the default behavior of the form.

Resources