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("/");
});
Related
I don't know how to connect the React app and Node.js server. In my React app I have an input with type="file" where I upload my CSV file and then I press the button to send this file to the Node.js server.
Update:
My server code:
var express = require('express');
var app = express();
const bodyParser = require("body-parser");
const CsvUpload = require("express-fileupload");
app.use(CsvUpload());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use('/EXPRESSENDPOINT',
(req, res, next) => { console.log(req.body)});
app.listen(8080, () => {
console.log('Application listening on port 8080!');
});
My App.js:
import './App.css';
import React, { useState, useEffect } from "react";
import axios from 'axios'
function App() {
const [csvFile, SetCsvFile] = useState();
return (
<div className="App">
<header className="App-header">
<div>
Select file
<input type="file" name="file" onChange={e => {
SetCsvFile(e.target.files)
const formData = new FormData();
formData.append('name', "FILENAME");
formData.append('file', csvFile);
const url = 'http://localhost:8080/EXPRESSENDPOINT';
axios({
method: 'POST',
url: url,
headers: {
ContentType: 'multipart/form-data'
},
body: formData
})
.then(res => console.log(res))
.catch(err => console.log(err));
}} />
</div>
</header>
</div>
);
}
export default App;
your react code would be,
const [csvFile, SetCsvFile] = useState();
const formData = new FormData();
formData.append('name', "FILENAME");
formData.append('file', csvFile);
<input type="file" name="file" onChange={SetCsvFile(e.target.files[0])} />
const url = 'http://localhost:8000/EXPRESSENDPOINT';
axios({
method: 'POST',
url: url,
headers: {
ContentType: 'multipart/form-data'
},
body: formData
})
.then(res => console.log(res))
.catch(err => console.log(err));
and nodejs backend is,
const bodyParser = require("body-parser");
const CsvUpload = require("express-fileupload");
app.use(CsvUpload());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use('/EXPRESSENDPOINT',
(req, res, next) => { console.log(req.body) });
extract out logic into function,
handleler = (e) => {
SetCsvFile(e.target.files[0])
}
<input type="file" name="file" onChange={handleler} />
or simply do this,
onChange={e => {
SetCsvFile(e.target.files)
}}
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.
I'm trying to create login/registration for an app using React/Node/Express/Postgres. Where I'm getting stuck is receiving data on the server side from my form in React.
I have a register component for the form in register.js
import React from 'react';
import useForm from '../form/useForm';
const Register = () => {
const { values, handleChange, handleSubmit } = useForm({
name: '',
email: '',
password: "",
password2: ""
}, register);
function register() {
console.log(values);
}
return (
<div className="row mt-5">
<div className="col-md-6 m-auto">
<div className="card card-body">
<h1 className="text-center mb-3">
<i className="fas fa-user-plus"></i> Register
</h1>
<form
action="/users/register"
method="POST"
onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="name">Name</label>
<input
className="form-control"
type="name"
name="name"
onChange={handleChange}
placeholder="Enter Name"
value={values.name}
required />
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<input
className="form-control"
type="email"
name="email"
onChange={handleChange}
placeholder="Enter Email"
value={values.email}
required />
</div>
<div className="form-group">
<label htmlFor="email">Password</label>
<input
className="form-control"
type="password"
name="password"
onChange={handleChange}
placeholder="Create Password"
value={values.password}
required />
</div>
<div className="form-group">
<label htmlFor="email">Confirm Password</label>
<input
className="form-control"
type="password"
name="password2"
onChange={handleChange}
placeholder="Confirm Password"
value={values.password2}
required />
</div>
<button type="submit" className="btn btn-primary btn-block">
Register
</button>
</form>
<p className="lead mt-4">Have An Account? Login</p>
</div>
</div>
</div>
);
};
export default Register;
A hook to handle the form actions in useForm.js
import {useState, useEffect} from 'react';
const useForm = (initialValues, callback) => {
const [hasError, setErrors] = useState(false);
const [values, setValues] = useState(initialValues);
const handleSubmit = (event) => {
if (event) event.preventDefault();
const options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(setValues(values => ({ ...values, [event.target.name]: event.target.value })))
}
fetch("/users/register", options)
}
const handleChange = (event) => {
event.persist();
setValues(values => ({ ...values, [event.target.name]: event.target.value }));
};
return {
handleChange,
handleSubmit,
values,
}
};
export default useForm;
Then I have a file to manage the routes for logging in/registering in users.js
const express = require("express");
const Router = require("express-promise-router");
const db = require("../db");
const router = new Router();
//Login page
router.get('/login', (req, res) => res.send("Login"));
//Register page
router.get('/register', (req, res) => res.send("Register"));
//Register Handle
router.post('/register', (req, res) => {
console.log(req.body);
res.send('hecks');
});
module.exports = router;
I have tried messing with things inside of the handleSubmit function in my useForm.js hook, but everything leads to the console.log(req.body) from my users.js file to return as undefined. Where am I going wrong?
Edit #1: Snip from Postman sending post request
Edit #2: basic project structure
.
./client
./client/src
./client/src/components
./client/src/components/register
./client/src/components/register/register.js
./client/src/components/form
./client/src/components/form/useForm.js
./client/src/App.js
./routes
./routes/index.js
./routes/users.js
./server.js
Edit #3: Main server.js file
const express = require("express");
const mountRoutes = require("./routes");
const app = express();
mountRoutes(app);
var bodyParser = require("body-parser");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
//catch all other routes
app.get("*", function(req, res) {
res.send("<h1>Page does not exist, sorry</h1>");
});
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`));
Youβre setting state in JSON.stringify which returns undefined. youβve to pass values in it:
const handleSubmit = (event) => {
if (event) event.preventDefault();
const options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(values)
}
fetch("/users/register", options)
}
You need to apply bodyParser before mounting routes.
So change like this:
var bodyParser = require("body-parser");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
mountRoutes(app);
You don't use then or await in the handleSubmit function which may cause problem.
Can you update the handleSubmit function like this and try?
const handleSubmit = async event => {
if (event) event.preventDefault();
const options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(values)
};
try {
const response = await fetch("/users/register", options);
const responseData = await response.json();
if (response.ok) {
console.log("response ok");
callback();
} else {
console.log("response NOT ok");
throw new Error(responseData.message);
}
} catch (err) {
console.log(err);
if (err.response) {
console.log(err.response.data);
}
}
};
π¨βπ« You can try with this code below:
userForm.js: Make sure your handleSubmit in your userForm.js it's looks like this code below: π
const handleSubmit = async(event) => {
if (event) event.preventDefault();
const options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(values)
}
try {
// change with your endpoint
const endpoint = 'http://localhost:3001/users/register';
const result = await fetch(endpoint, options);
// send value to your register function
callback(result);
} catch (ex) {
console.log('Something failed');
console.log(ex);
}
}
You've to use callback(result), so you can console.log that value on your register function.
express server: Make sure in your express server, you've been add body-parser, it's will looks like this code below: π
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
That code above will make your req.body works.
I hope it can help you π.
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.
I am creating a login page, and the problem is that express creating a new session each time a request comes from the frontend app. I have checked and tried all the other answers on the net and here at SO. The part that bugs me most is that it works with curl, but not via the frontend app.
Here is the code:
server.js
const bodyParser = require('body-parser');
const cors = require('cors');
const session = require('express-session')
const cookieParser = require('cookie-parser');
const express = require('express');
const app = express();
app.use(cors());
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({extended: true})); // for parsing application/x-www-form-urlencoded
app.use(cookieParser('keyboard cat'));
app.set('trust proxy', true);
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
httpOnly: true,
cookie: {secure: false}
}));
app.get('/secured', function (req, res) {
res.header("Access-Control-Allow-Origin", "http://localhost:3006");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Cookie");
if (req.session) {
console.log("has session", req.session);
if (req.session.loggedInUser) {
res.status(200).end("OK");
} else {
res.status(401).end("NOTOK1");
}
} else {
res.status(401).end("NOTOK2");
}
});
const users = [
{email: 'foo#bar.com', pass: 'foo'}
];
app.post('/login', function (req, res) {
const matched = users.filter(e => e.email === req.body.loginEmail && e.pass === req.body.loginPassword);
if (matched === undefined || matched.length === 0) {
res.status(401).end('NOTOK');
} else {
req.session.loggedInUser = matched[0];
req.session.save();
res.status(200).end('OK');
}
});
app.listen(8000, () => {
console.log('Started, listening');
});
And the login component from the frontend (React).
import React from "react";
import {MDBBtn, MDBCol, MDBContainer, MDBRow} from 'mdbreact';
import axios from 'axios';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {error:{}};
this.handleLogin = this.handleLogin.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleLogin(event) {
event.preventDefault();
let state = this.state;
let registerFormInputs = Object.keys(this.state).filter(v => v.startsWith("login"));
const data = {};
registerFormInputs.forEach(function (input) {
data[input] = state[input];
});
axios.post('http://localhost:8000/login', data)
.then(function (response) {
axios.get('http://localhost:8000/secured', {withCredentials: true})
.then(resp => {
console.log(resp);
});
})
.catch(err => {
this.setState({error: err.response})
})
}
handleChange(event) {
this.setState({[event.target.id]: event.target.value});
}
render() {
return (
<MDBContainer>
<MDBRow>
<MDBCol md="6">
<form onSubmit={this.handleLogin}>
<p className="h4 text-center mb-4">Log in</p>
{this.state.error.data ? <div>{this.state.error.data}</div> : null}
<label htmlFor="loginEmail" className="grey-text">
Email
</label>
<input
type="email"
id="loginEmail"
className="form-control"
onChange={this.handleChange}
/>
<br/>
<label htmlFor="loginPassword" className="grey-text">
Password
</label>
<input
type="password"
id="loginPassword"
className="form-control"
onChange={this.handleChange}
/>
<div className="text-center mt-4">
<MDBBtn color="indigo" type="submit">Login</MDBBtn>
</div>
</form>
</MDBCol>
</MDBRow>
</MDBContainer>
);
}
}
export default Login;
The frontend:
https://codesandbox.io/s/2vor7xproj
The backend:
https://codesandbox.io/s/j755x416j9
I dont generally handle sessions directly. I let passportJS deal with that.
However, in the session constructor saveUninitialized is generally set to false when dealing with login events or trying to deal with race conditions in parallel requests.
From express-session npm
saveUninitialized
Forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified. Choosing false is useful for implementing login sessions, reducing server storage usage, or complying with laws that require permission before setting a cookie. Choosing false will also help with race conditions where a client makes multiple parallel requests without a session.
The default value is true, but using the default has been deprecated, as the default will change in the future. Please research into this setting and choose what is appropriate to your use-case.