I am developing a simple MERN app. I am trying to connect the both ends and post data on server onSubmit(). I am able to access the server URL directly.However, I am getting POST http://localhost:1337/api/register 404 (Not Found) when requesting it from React page.
Any kind of help will be appreciated
Thanks
server/index.js
const express = require('express')
const app = express()
const cors = require('cors')
app.use(cors())
app.use(express.json())
app.get('/api/register', (req, res) =>{
console.log(req.body)
res.json({status:'ok'})
})
app.listen(1337,() =>{
console.log('Server started on 1337')
})
client/App.js
import './App.css';
import {useState} from 'react';
function App() {
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
async function registerUser(event){
event.preventDefault()
const response = await fetch('http://localhost:1337/api/register',{
method:'POST',
headers:{
'Content-Type': 'application/json',
},
body:JSON.stringify({
name,
email,
password
}),
})
const data = await response.json()
console.log(data)
}
return (
<div>
<h1>Register</h1>
<form onSubmit = {registerUser}>
<input
value = {name}
onChange = {(e)=> setName(e.target.value)}
type="text"
placeholder="Name"/>
<br/>
<input
value = {email}
onChange = {(e)=> setEmail(e.target.value)}
type="email"
placeholder="Email"/>
<br/>
<input
value = {password}
onChange = {(e)=> setPassword(e.target.value)}
type="password"
placeholder="Password"/>
<br/>
<input type = "submit" value = "Register"/>
</form>
</div>
);
}
export default App;
Thanks
const express = require('express')
const app = express()
const cors = require('cors')
app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: false }));
app.post('/api/register', (req, res) =>{
console.log(req.body)
res.json({status:'ok'})
})
app.listen(1337,() =>{
console.log('Server started on 1337')
})
For the post request, we must tell our API requests that it is POST so we must initialize our request with the POST method.
Related
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?
So I have a login form that currently looks like that :
import React, { useState, useEffect} from "react";
import { Form, Button, Row, Col } from "react-bootstrap";
import { Link } from "react-router-dom";
import "./LoginScreen.css";
import axios from 'axios';
function LoginScreen() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const submitHandler = async (e) => {
e.preventDefault();
try {
const config = {
headers: {
"Content-type": "application/json",
},
}
setLoading(true)
const { data } = await axios.post(
'/api/users/login',
{
email, password,
},
config);
console.log(data);
localStorage.setItem("userInfo", JSON.stringify(data));
setLoading(false);
} catch (error) {
setError(error.response.data.message);
}
}
return (
<div className="login_outer">
<h1>Login Here</h1>
<div className="loginContainer">
<Form onSubmit={ submitHandler }>
<Form.Group controlId="formBasicEmail" >
<Form.Label>E-mail: </Form.Label>
<Form.Control size="lg" type="email" value={email} placeholder="Enter Email" className="input" onChange={(e) => setEmail(e.target.value)}/>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password: </Form.Label>
<Form.Control size="lg" type="password" value={password} placeholder="Enter Password" className="input" onChange={(e) => setPassword(e.target.value)}/>
</Form.Group>
<Button className="login_button" variant="primary" type="submit">
Submit
</Button>
</Form>
<Row className="py-3">
<Col>
New User ? <Link to="/register">Register Here</Link>
</Col>
</Row>
</div>
</div>
);
}
export default LoginScreen;
When I click the submit button I get the error:
POST http://localhost:3000/api/users/login 404 (Not Found)
In my server.js I have:
const userRoutes = require('./routes/userRoutes.js');
const dotenv = require('dotenv');
const express = require('express');
const connectDB = require('./config/db');
const { notFound, errorHandler } = require('./middlewares/errorMiddleware');
dotenv.config();
connectDB();
const app = express();
app.use(express.json());
app.get("/", (req, res) => {
res.send("API is running..");
});
app.use('/api/users', userRoutes);
app.use(notFound);
app.use(errorHandler);
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server started on PORT ${PORT}`));
and in my routes I have:
const express = require('express');
const { registerUser, authUser } = require('../controllers/userControllers');
const router = express.Router();
router.route('/').post(registerUser);
router.post("/login", authUser);
module.exports = router;
Any idea why this is happening and how to fix it ? I think it is something to do with the server file.
UPDATE!: I have fixed the error by getting a proxy, but now I when I try to login I get 401 unauthorized. Anyone know how to fix that?
Delete "proxy": "http://localhost:3000". Install package http-proxy-middleware with command:
npm install http-proxy-middleware --save
Create a file setupProxy.js inside your src folder or the root of your folder. Add these lines inside:
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
createProxyMiddleware({
target: 'http://localhost:5000',
changeOrigin: true,
})
);
};
This is my express server
const express = require("express");
const app = express();
const mongoose = require("mongoose");
require("dotenv").config();
const cors = require("cors");
const userData = require("./db");
var PORT = process.env.PORT || 3001;
app.use(cors());
app.use(express.urlencoded({ extended: false }));
mongoose
.connect("mongodb://localhost", {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log("Connected to database!!");
})
.catch((e) => {
console.log("Error : " + err);
});
app.get("/", (req, res) => {
res.json({ server: "Running" });
});
app.get("/login", (req, res) => {
res.json({ user: "true" });
});
app.post("/signup", (req, res) => {
console.log(req);
res.redirect("/");
});
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
and this is my React component
import React, { useState } from "react";
import "./Signup.css";
import axios from "axios";
import { useSelector } from "react-redux";
import { selectAuth } from "../../features/authSlice";
export default function Login() {
const isAuthenticated = useSelector(selectAuth);
const [user, setUser] = useState("");
const [pass, setPass] = useState("");
const handleSignup = async (e) => {
e.preventDefault();
var bodyFormData = new FormData();
bodyFormData.append("username", user);
bodyFormData.append("password", pass);
const res = await axios({
method: "post",
url: "http://localhost:3001/signup",
data: bodyFormData,
headers: { "Content-Type": "multipart/form-data" },
});
};
return (
<div className="signup__container">
<h2>Signup</h2>
<form className="signup__form" autoComplete="off">
<div className="signup__imgContainer">
<img
src={require("../../assets/avatar-placeholder.jpg").default}
alt="Avatar"
className="signup__avatar"
/>
</div>
<div className="signup__inputContainer">
<label for="uname">
<b>Username</b>
</label>
<input
type="text"
placeholder="Enter Username"
name="uname"
onChange={(e) => setUser(e.target.value)}
required
/>
<label for="psw">
<b>Password</b>
</label>
<input
type="password"
placeholder="Enter Password"
name="psw"
required
onChange={(e) => setPass(e.target.value)}
/>
<button type="submit" onClick={handleSignup}>
Signup
</button>
<label>
<input type="checkbox" name="remember" /> Remember me
</label>
</div>
</form>
<div>{isAuthenticated.toString()}</div>
</div>
);
}
I am trying to post data using axios but I am unable to access this data in my backend. Am i doing it right, if yes then can anyone tell me what's wrong. and if no then how can I correct it to use the data.
I tried various things like sending the data as params but nothing worked on server it was always undefined however the console.log(req) gives something but I didn't see any of my post data in it.
add app.use(express.json());
if it does not work. then add body-parser in your package.
const express = require("express");
const bodyParser = require("body-parser"); // install body-parser
const cors = require("cors");
const app = express();
app.use(bodyParser.json({ limit: "50mb" }));
app.use(
bodyParser.urlencoded({
limit: "50mb",
extended: true,
parameterLimit: 50000,
})
);
app.use(express.json()); /// add
In the React app, you're using Content-Type multipart/form-data. When you use this Content-Type, the server needs to parse the request differently. This Content-Type is used when you want to upload a file in the request. It isn't the case here, so you should use Content-Type application/json instead.
Your request should be:
const res = await axios({
method: "post",
url: "http://localhost:3001/signup",
data: { username : user, password : pass},
headers: { "Content-Type": "application/json },
});
And in the Express application, you need to add a middleware to parse incoming requests in application/json Content-Type.
app.use(cors());
app.use(express.urlencoded({ extended: false }));
app.use(express.json()); // <---- add this
In the route, you can see the data inside req.body
app.post("/signup", (req, res) => {
console.log(req.body);
res.redirect("/");
});
I set the cors module but it still getting this problem,this what i get in the browser console:
login:1 Access to fetch at 'http://localhost:3001/login' from origin 'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
POST http://localhost:3001/login net::ERR_FAILED
Uncaught (in promise) TypeError: Failed to fetch.
this is my frontend:
import React, {SyntheticEvent, useState} from 'react';
import {Redirect} from "react-router-dom";
const Login = (props: { setName: (name: string) => void }) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [redirect, setRedirect] = useState(false);
const submit = async (e: SyntheticEvent) => {
e.preventDefault();
const response = await fetch('http://localhost:3001/login', {
method: 'POST',
credentials: 'include',
body: JSON.stringify({
email,
password
})
});
const content = await response.json();
setRedirect(true);
props.setName(content.name);
}
if (redirect) {
return <Redirect to="/"/>;
}
return (
<form onSubmit={submit}>
<h1 className="h3 mb-3 fw-normal">Please sign in</h1>
<input type="email" className="form-control" placeholder="Email address" required
onChange={e => setEmail(e.target.value)}
/>
<input type="password" className="form-control" placeholder="Password" required
onChange={e => setPassword(e.target.value)}
/>
<button className="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
</form>
);
};
export default Login;
this is my backend:
const express = require('express')
const mongoose = require('mongoose')
const bodyParser = require('body-parser')
const routes = require('./routes')
const cors = require("cors");
mongoose.connect('mongodb://127.0.0.1:27017/passport-jwt', {
useUnifiedTopology: true,
useNewUrlParser: true,
useCreateIndex: true,
})
const app = express()
app.use(cors({origin:'http://localhost:3000'}))
require('./auth/auth')
app.use(bodyParser.json())
app.use(routes)
const PORT = 3001
app.listen(PORT, function () {
console.log(`App listening on ${PORT}`)
})
In the Express documentation here
credentials: Configures the Access-Control-Allow-Credentials CORS
header. Set to true to pass the header, otherwise it is omitted.
Because you include the credentials in the request, in the backend, you need to add option "credentials" to pass the header. Replace :
app.use(cors({origin:'http://localhost:3000'}))
by :
app.use(cors({origin:'http://localhost:3000', credentials : true}));
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.