Req.Body undefined NODE.JS POST Request - javascript

I'm currently working on a simple Node.JS app that communicates with mysql database.
The app gets data from the database and puts it in a table using app.get and it works fine.
The problem I am having is that req.body is not returning anything when using app.post. The app will submit to the database, but because req.body is not returning anything, the values are null. It will post actual values if I swap the req.body variables with hardcoded variables e.g. "12320".
I have therefore isolated the problem to post requests which use req.body.
If I console log req.body it is empty.
I have read just about every stackoverflow question on this and have not been able to find a solution.
I have tried reinstalling body-parser, express, morgan, and mysql.
I have tried recreating the app in a fresh directory and installing the modules again.
I have tried renaming the variables incase that was having some effect (e.g. name="test", req.body.test)
But all of this was to no avail.
<form id="submit_missing" action="/submit_quote" method="POST" enctype="multipart/form-data">
<input type="text" id="submit_quote_id" name="submit_quote_id" placeholder="Quote ID">
<input type="text" id="submit_priority" name="submit_priority" placeholder="Priority" list="priority_list">
<input type="text" id="submit_customer" name="submit_customer" placeholder="Customer">
<input type="text" name="submit_who" id="submit_who" placeholder="Who's On it" list="purchasing">
<input type="text" id="submit_account_manager" name="submit_account_manager" placeholder="Account Manager" list="account_managers">
<button id="submit_quote">SUBMIT</button>
<form>
// server.js
const express = require('express')
const app = express()
const morgan = require('morgan')
const mysql = require('mysql')
const bodyParser = require('body-parser')
app.use(bodyParser.json({ type: '*' }))
app.use(bodyParser.urlencoded({ extended: true }))
app.use(express.static('./public'))
app.use(express.static('./files'))
const user = ***
const pass = ***
function getBoardConnection() {
return mysql.createConnection({
host: "localhost",
port: "3306",
user: user,
password: pass,
database: "board"
})
}
app.get('/get_board_quotes', (req, res) => {
const con = getBoardConnection()
const queryString = "SELECT * FROM board_quotes WHERE quote_complete = '0'"
con.query(queryString,(err, rows, fields) => {
if (err) {
console.log("Failed to query for /get_board_quotes : " + err)
}
console.log("Getting data from database for /get_board_quotes")
res.json(rows)
})
})
app.post('/submit_quote/', (req, res) => {
console.log(req.body)
quote_id = req.body.submit_quote_id
priority = req.body.submit_priority
customer = req.body.submit_customer
who_quoted = req.body.submit_who
account_manager = req.body.submit_account_manager
type = ""
queryString = "INSERT INTO board_quotes (quote_id, priority, customer, who_quoted, account_manager, quote_type) \
VALUES (?, ?, ?, ?, ?, ?)"
getBoardConnection().query(queryString, [quote_id, priority, customer, who_quoted, account_manager, type], (err, results, field) => {
if (err) {
console.log("Failed to insert new board order " + err)
return res.redirect('/board/quotes.html')
}
console.log("Inserted a new board with id ")
res.redirect('/board/quotes.html')
})
})
app.listen(6565, () => {
console.log("Server is running")
})
Output
Server is running
Getting data from database for /get_board_quotes
{}
Failed to insert new board order Error: ER_BAD_NULL_ERROR: Column 'quote_id' cannot be null
{} is the output for console.log(req.body)
Any help would be greatly appreciated.

The issue you’re having is that you’ve set enctype="multipart/form-data" on your <form> HTML tag. By default, body-parser doesn’t parse bodies with a Content-Type header of multipart/form-data, which is what you’re telling the browser to send.
There is an easy way to fix this: I’d recommend just not setting enctype on the <form> element, as the browser will default to application/x-www-form-urlencoded and this is the type of form body body-parser will parse by default.
You can otherwise try passing type: "multipart/form-data" as an option when you call bodyParser.urlencoded(), which will make body-parser parse anything sent to it with that content type. (Correction: body-parser actually just silently fails for me if I tell it to parse multipart/form-data)
This question/answer may be of further help.

Body parser does not work with : Content-Type:multipart/form-data header
Multer is used to handle Content-Type:multipart/form-data header , while uploaing file with form-data
Body Parser only work with :
Content-Type:application/x-www-form-urlencoded ,
Content-Type:application/json
remove enctype="multipart/form-data" in your form & try to submit form

At first I would recommend to use curl utility to simplify POST request, issue the following (I'm assuming here that you calling from the same machine hence 'localhost'):
curl -d "submit_quote_id=999" -X POST http://localhost:6565/
and see what you get

Related

Cannot POST /login error - while clicking submit using Node.js and Express.js with MySql

I am trying to build simple login page using node.js with express.js package and mysql package, that will redirect the user to layout.html page, if the username and password exists in mysql database.
I run mysql on my localhost, and I've created a database with tables and users in mysql workbench.
The node.js server is also being run on localhost using liteserver.
After I am clicking on "Submit" button on my page, no matter if there is any data written into (username) and (password) boxes, I am getting an Error saying "Cannot POST /login"
That is all the code I have, all my javascript code is in one file.
**script.js
**
import express from 'express';
const app = express();
import { createConnection } from 'mysql';
import bodyParser from 'body-parser';
const router = express.Router();
// Create a connection to the MySQL server
const connection = createConnection({
host: 'localhost', // The hostname of the MySQL server
user: 'pablo', // The username to connect to the server
password: 'KotWButach!', // The password for the usernam
database: 'logowanie' // The name of the database
});
// Connect to the MySQL server
connection.connect();
connection.connect((err) => {
if (err) {
console.error(`Error connecting to the database: ${err.stack}`);
return;
}
console.log(`Connected to the database with id: ${connection.threadId}`);
});
connection.query(query, (error, results) => {
if (error) {
console.error(`Error executing the query: ${error.stack}`);
return res.status(500).send({ error });
}
});
// Parse the request body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
router.post('/login');
app.post('/login', (req, res) => {
const { username, password } = req.body; // Destructure the username and password from the request body
// Query the users table to check if the provided username and password match a record in the table
const query = `SELECT * FROM users WHERE UserName = '${username}' AND UserPass = '${password}'`;
connection.query(query, (error, results) => {
if (error) {
return res.status(500).send({ error });
}
if (results.length === 0) {
return res.status(401).send({ message: 'Invalid username or password' });
}
// If the username and password match a record in the table, redirect to the layout.html page
res.redirect('/layout.html');
});
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
index.html
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-randomvalue'">
<head>
<link rel="stylesheet" type="text/css" href="styles.css">
<title>Login</title>
<script nonce="randomvalue" src="script.js"></script>
</head>
<body>
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username">
<br>
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
I am expecting it to be able to redirect to layout.html after clicking submit (with credentials that match with the ones in the database), or get an error saying "invalid username or password" it they aren't matching.
I've scrolled through more than 30 cases on stackoverflow and none of the answers seem to work or me, I've even asked ai for what to do but it got stuck on the loop telling me to check if my routing is correct.
You could simply remove theses lines in your code that cause the error that you have :
Remove just this line :
router.post('/login');
You declare a api endpoint which has no callback behind and point to "/login", that's why you have the error.
After remove it, you can also remove the router you declare previously as you won't need it anymore.

Backend post request only reads as "undefined" JS

I am pretty new to JS so please go easy on me.
Im trying to increment a value in a JSON file in my JS backend application. Whenever I increment the associated value by the key, it creates a new section "undefined"
Here is the entire application:
const { response } = require("express");
const express = require("express");
const fs = require("fs").promises;
const path = require("path");
const app = express();
const dataFile = path.join(__dirname, "data.json");
//support POSTing form data wuth url encoded
app.use(express.json());
app.get("/poll", async (req, res) =>{
//data is now the js object of the Json data json
let data = JSON.parse(await fs.readFile(dataFile, "utf-8"));
const totalVotes = Object.values(data).reduce((total, n) => total +=n, 0);
data = Object.entries(data).map(([label, votes]) => {
return{
label,
percentage: (((100 * votes) / totalVotes) || 0).toFixed(0) // or with 0 in the even that you divide by zero
}
});
res.json(data);
});
app.use(express.urlencoded({ extended: true}));
app.post("/poll", async (req, res) => {
const data = JSON.parse(await fs.readFile(dataFile, "utf-8"));
data[req.body.add]++;
await fs.writeFile(dataFile, JSON.stringify(data));
res.json(data);
});
app.listen(3000, () => console.log("Server is running ..."));
Here is my JSON file before I POST
{
"JavaScript":0,
"TypScript":10,
"Both":3}
Here is a picture of my POST request in Insomnia:
Here is my JSON file after a Post Requests
{
"JavaScript": 0,
"TypScript": 10,
"Both": 3,
"undefined": null
}
Here is is after a second POST request:
{
"JavaScript": 0,
"TypScript": 10,
"Both": 3,
"undefined": 1
}
I know it might be something very simple, but I am very inexperienced so any help would be greatly appreciated!
I tried including some additional middleware to enable bodyParsing as I saw in other posts but that did not fix the issue.
I also tried
console.logging(req.body)
,but that only printed "undefined".
EDIT:
I found the problem, I wasn't sending the information in Insomnia correctly, I need to click the form type and either format a JSON input or select the "Form URL Encoded"" Option. Otherwise it doesn't recognize the format.
Thank you for your help!
I tried your code in my device, it works fine on my device which means you are not properly sending post request.
And there is a bug in your logic of adding name , in which you increment the add property of data object but that property is not a number but a null so the number does not increments. Here is a simple fix...
app.post("/poll", async (req, res) => {
const data = JSON.parse(await fs.readFile(dataFile, "utf-8"));
let {add} = req.body;
if(data[add] === 0 || data[add]) data[add]++;
else data[add] = 0;
await fs.writeFile(dataFile, JSON.stringify(data));
res.json(data);
});
If req.body printed "undefined", req.body.add will also be equal to "undefined".
This is causing the error. I haven't used Insomnia but when you send your POST request your "body" needs to be something like this:
{
"add": "variableName"
}

how to get cookie in react passed from express js api (MERN stack)

I have an api in express js that stores token in cookie on the client-side (react). The cookie is generated only when the user logins into the site. For example, when I test the login api with the postman, the cookie is generated as expected like this:
But when I log in with react.js then no cookie is found in the browser. Looks like the cookie was not passed to the front end as the screenshot demonstrates below:
As we got an alert message this means express api is working perfectly without any error!!
Here is my index.js file on express js that includes cookie-parser middleware as well
require("dotenv").config();
const port = process.env.PORT || 5050;
const express = require("express");
const app = express();
const cors = require("cors");
const authRouter = require("./routes/auth");
var cookieParser = require('cookie-parser')
connect_db();
app.use(express.json());
app.use(cookieParser())
app.use(cors());
app.use("/" , authRouter);
app.listen(port , () => {
console.log("Server is running!!");
})
Code for setting up the cookie from express api only controller
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require('bcrypt')
const login = async (req, res) => {
const { email, password } = req.body;
try {
const checkDetails = await User.findOne({ email });
if (checkDetails) {
const { password: hashedPassword, token, username } = checkDetails;
bcrypt.compare(password, hashedPassword, function (err, matched) {
if (matched) {
res.cookie("token", token, { expires: new Date(Date.now() + (5 * 60000)) , httpOnly: true }).json({ "message": "You logged in sucessfully!" });
} else {
res.status(500).json({ "message": "Wrong password" });
}
});
} else {
res.status(500).json({ "message": "Wrong email" });
}
} catch (error) {
console.log(error.message);
}
}
Here is the react.js code that I am using to fetch data from api without using a proxy in package.json file
if (errors.length === 0) {
const isLogin = await fetch("http://localhost:5000/api/login", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: {
"Content-Type": "application/json"
}
});
const res = await isLogin.json();
if(res) alert(res.message);
}
I want to get to know what is the reason behind this "getting cookie in postman but not in the browser". Do I need to use any react package?
The network tab screenshot might help you.
If I see in the network tab I get the same cookie, set among the other headers
To my understanding, fetch doesn't send requests with the cookies your browser has stored for that domain, and similarly, it doesn't store any cookies it receives in the response. This seems to be the expected behaviour of fetch.
To override this, try setting the credentials option when making the request, like so:
fetch(url, {
// ...
credentials: 'include'
})
or, alternatively:
fetch(url, {
// ...
credentials: 'same-origin'
})
You can read more about the differences between the two here.
I got my error resolved with two changings in my code
In front end just added credentials: 'include'
fetch(url, {
method : "POST"
body : body,
headers : headers,
credentials: 'include'
})
And in back end just replaced app.use(cors()); to
app.use(cors({ origin: 'http://localhost:3000', credentials: true, exposedHeaders: ['Set-Cookie', 'Date', 'ETag'] }))
That's it got resolved, Now I have cookies stored in my browser!!! Great. Thanks to this article:
https://www.anycodings.com/2022/01/react-app-express-server-set-cookie-not.html
during development i also faced same things, let me help you that how i solve it,
Firstly you use proxy in your react package.json, below private one:-
"private": true,
"proxy":"http://127.0.0.1:5000",
mention the same port on which your node server is running
Like:-
app.listen(5000,'127.0.0.1',()=>{
console.log('Server is Running');
});
above both must be on same , now react will run on port 3000 as usual but now we will create proxy to react So, react and node ports get connected on same with the help of proxy indirectly.
Now, when you will make GET or POST request from react then don't provide full URL, only provide the path on which you wants to get hit in backend and get response,
Example:-
React side on sending request, follow like this:-
const submitHandler=()=>{
axios.post('/api/loginuser',
{mobile:inputField.mobile,password:inputField.password})
.then((res)=>{
console.log(res);
})
.catch((err)=>{
console.log(err);
})
}
Node side where it will hit:-
app.post('/api/loginuser', async(req,res)=>{
//Your Code Stuff Here
res.send()
}
on both side same link should hit, it is very important
it will 100%.
don't forget to mention
on node main main where server is listening

How to take clientside Javascript arrays and POST through a Node.js API into a MongoDB database?

I have a single webpage that initially has two form inputs, one for a list of names and another for the title of a game. I've written some javascript/jquery that takes the X names and creates X more form inputs meant for each person's specific score. The javascript then creates the following variables upon the clicking of the names/scores form's submit button:
gameTitle = Monopoly
users = [Bob, Bill, Jim, Janet]
scores = [100, 110, 90, 80]
positions = [2, 1, 3, 4]
I then have a MongoDB schema set up as such:
const SessionSchema = new mongoose.Schema({
gameTitle: String,
users: [],
scores: [],
positions: []
});
And a Node.js handler as such:
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
const timestamps = require('mongoose-timestamp');
router.use(bodyParser.urlencoded({ extended: true }));
router.use(bodyParser.json());
const Session = require('./Session');
//Post a session to the database
router.post('/', function(req, res) {
Session.create({
gameTitle : req.body.gameTitle,
users : req.body.user,
scores : req.body.score,
positions : req.body.position
},
function (err, session) {
if (err) return res.status(500).send("There was a problem adding the information to the database");
res.status(200).send(session);
});
});
Using Postman I can see that posting works when I use this format:
Postman POST
Postman GET
How do I take the created javascript variables and, also upon the clicking of the names/scores form's submit button, POST them through the API and into the MongoDB database?
Apologies if I have missed any important information/code - I haven't fully wrapped my head around how the backend stuff works.
You need to register your Schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const SessionSchema = new mongoose.Schema({
gameTitle: String,
users: [],
scores: [],
positions: []
});
module.exports = mongoose.model('session', SessionSchema);
And here you need to use the mongo schema model, like this:
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
const timestamps = require('mongoose-timestamp');
router.use(bodyParser.urlencoded({ extended: true }));
router.use(bodyParser.json());
const SessionSchema = require('./Session'); // register the mongo model
const mongoose = require('mongoose');
const Session = mongoose.model('session');
//Post a session to the database
router.post('/', function(req, res) {
const new_session = {
gameTitle : req.body.gameTitle,
users : req.body.user,
scores : req.body.score,
positions : req.body.position
};
new_session.save((err, saved_session) => {
if(err) {
res.json(err);
} else {
res.json(saved_session);
}
});
});
Sounds like you have the backend working. What you're missing is the API request. Since your website is not under the same host:port than your API server, when doing it from the browser you'll face CORS issues. Let's get to that later:
First, you'll be making an API call. You can use axios or fetch. Let's go with fetch here:
fetch(url, {
body: JSON.stringify(yourJavascriptVariablesAsAnObject),
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
})
.then(response => {
// here you can check for status if you want.
// ...
return response.json(); // assuming server returns JSON.
})
.then(responseBody => {
// Do something with the server's response body
});
Now for the CORS problem, if your client app is from create-react-app or at least you're using webpack-dev-server, you can proxy request really easy.
If you're not, then you need to allow CORS on your nodeJS server. The simplest way is to use a library.
PS: CORS basically means you can't do requests from a browser to a service living in a different `url:port:, unless that service explicitly says it's ok.
A third option would be putting both UI and server project behind a Web server like Nginx and proxy the requests, but that sounds too complex for what you need.

Bodyparser is incorrectly parsing JSON?

I'm using the body-parser NPM module with Express to parse json on my server, but for some reason, the JSON is showing up incorrectly on the server. Here is my server code:
...
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
...
app.route("/schedule")
.get(function(req, res) {
...
})
.post(function(req, res) {
var schedule = req.body.schedule;
console.log(req.body);
if(schedule) {
setSchedule(schedule);
res.status(200).end();
}
});
And my client code:
var schedule = {
entries: entries
};
var str = JSON.stringify(schedule);
console.log("Submitting schedule:",str);
post("/schedule", str)
.then((res) => {
this.completed(res.json);
})
.catch((res) => {
this.failed(res.text);
});
When I POST the data from the client, the client prints this:
Submitting schedule: {"entries":[1430014800000,1430055600000,1430104620000,1430146380000,1430194140000,1430236920000,1430283120000,1430326860000,1430371740000,1430416380000,1430460180000,1430505480000,1430548500000,1430594460000,1430636760000,1430683260000,1430725020000,1430772060000,1430813340000,1430860920000,1430901720000,1430949900000,1430990340000,1431039060000,1431079200000,1431128520000,1431168480000,1431218220000,1431258360000,1431308160000,1431349020000,1431398040000,1431440220000,1431487800000,1431531360000,1431577260000,1431622140000,1431666540000,1431712440000,1431755640000,1431802320000,1431844680000,1431891960000,1431933660000,1431981360000,1432022580000,1432070700000,1432111560000,1432159980000,1432200540000,1432249260000,1432289580000,1432338600000,1432378860000,1432428060000,1432468500000,1432517520000,1432558560000]}
Which appears to be valid JSON, but on the server, req.body is this:
{ '{"entries":': { '1430014800000,1430055600000,1430104620000,1430146380000,1430194140000,1430236920000,1430283120000,1430326860000,1430371740000,1430416380000,1430460180000,1430505480000,1430548500000,1430594460000,1430636760000,1430683260000,1430725020000,1430772060000,1430813340000,1430860920000,1430901720000,1430949900000,1430990340000,1431039060000,1431079200000,1431128520000,1431168480000,1431218220000,1431258360000,1431308160000,1431349020000,1431398040000,1431440220000,1431487800000,1431531360000,1431577260000,1431622140000,1431666540000,1431712440000,1431755640000,1431802320000,1431844680000,1431891960000,1431933660000,1431981360000,1432022580000,1432070700000,1432111560000,1432159980000,1432200540000,1432249260000,1432289580000,1432338600000,1432378860000,1432428060000,1432468500000,1432517520000,1432558560000]': '' } }
which is an object that's only key is {"entries": and the value for that key is an object that's only key is an array of timestamps that should be sent as the value to entries.
Any help would be greatly appreciated.
It appears the module I'm using for making requests (superagent) automatically stringifies data, so the issue went away when I stopped stopped using JSON.stringify.
In my case, the issue was that I was making the request from the front end using AngularJS, and the default POST format was set to url-encoded:
$httpProvider.defaults.headers.post = {'Content-type': 'application/x-www-form-urlencoded'};
By default, it's set to 'application/json', so I just removed this line, after which the JSON then resolved correctly.

Categories