Post request body returning undefined - javascript

I'm making a post request using axios and passing in a body like so:
export const uploadFeatured = (userId, uploadInfo) => async dispatch => {
////console.log("uploading", uploadInfo.mediaName, uploadInfo.video, uploadInfo.description);
const res = await axios.post(domain + '/api/uploadFeatured',
{mediaName: uploadInfo.mediaName,
video: uploadInfo.video,
description: uploadInfo.description});
console.log("response to upload", res)
}
However, at the server, I'm getting an undefined when accessing req.body.
app.post("/api/uploadFeatured", async (req, res) => {
try {
//////// req.body returning undefined.
console.log("upload featured is ", req.body)
const data = {name:"Name"}
const newFeatured = new Featured(data).save();
const client = algoliasearch('YD', '055b10');
const index = client.initIndex('Humboi');
index.saveObjects([data], {
autoGenerateObjectIDIfNotExist: true
}).then(({ objectIDs }) => {
console.log(objectIDs);
});
console.log("new featured is ", newFeatured);
} catch (e) {
console.log("error ", e)
}
});
What am I doing that's causing the body to be undefined in the node.js server rather than to be the map that's passed in axios?

Please install body-parser add following code in your js file after const path:
npm install body-parser
const bodyParser = require('body-parser')
app.use(bodyParser);
The bodyParser object exposes various factories to create middlewares. All middlewares will populate the req.body property with the parsed body when the Content-Type request header matches the type option, or an empty object ({}) if there was no body to parse, the Content-Type was not matched, or an error occurred.

Related

Bind problem in SQL query in Node, Express, Mysql2 app

I have been following a tutorial on setting up REST APIs in Node, using Express for an app that accesses an existing MariaDB database. My version only needs to read data and I have the DB co-located with the Node application (same host).
My goal for this entry-level example is to just access the data, using static SQL, so I can see it rendered in the web page by the JSON pritifier.
[Next, I want to present the data in a table (EJS?). Later, when I can get that to work, I'll add form controls (React?) to let a user specify start and end date bounds for the SQL query. Finally I'll aim to render the data as a line graph (D3js).]
The tutorial runs the web server successfully (it returns 'OK' on the base URL), but when I go to URL/solarData it tries an async function to getMultiple rows from the DB, it responds:
Bind parameters must not contain undefined. To pass SQL NULL specify JS null TypeError: Bind parameters must not contain undefined. To pass SQL NULL specify JS null
at /SunnyData/solarViz/node_modules/mysql2/lib/connection.js:628:17
at Array.forEach (<anonymous>)
at Connection.execute (/SunnyData/solarViz/node_modules/mysql2/lib/connection.js:620:22)
at /SunnyData/solarViz/node_modules/mysql2/promise.js:120:11
at new Promise (<anonymous>)
at PromiseConnection.execute (/SunnyData/solarViz/node_modules/mysql2/promise.js:117:12)
at Object.query (/SunnyData/solarViz/services/db.js:6:40)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async Object.getMultiple (/SunnyData/solarViz/services/solarData.js:7:16)
at async /SunnyData/solarViz/routes/solarData.js:8:14
app.js:61
./app.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3800;
const solarDataRouter = require('./routes/solarData');
app.use(express.json());
app.use(
express.urlencoded({
extended: true,
})
);
app.get('/', (req, res) => {
res.json({'message': 'ok'});
})
app.use('/solarData', solarDataRouter);
/* Error handler middleware */
app.use((err, req, res, next) => {
const statusCode = err.statusCode || 500;
console.error(err.message, err.stack);
res.status(statusCode).json({'message': err.message});
return;
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
});
./routes/solarData.js
const express = require('express');
const router = express.Router();
const solarData = require('../services/solarData');
/* GET solar data. */
router.get('/', async function(req, res, next) {
try {
res.json(await solarData.getMultiple(req.query.page));
} catch (err) {
console.error(`Error while getting solar data `, err.message);
next(err);
}
});
module.exports = router;
./config.js
const env = process.env;
const config = {
db: {
host: env.SUNNY_HOST,
user: env.SUNNY_USER,
password: env.SUNNY_PW,
database: env.SUNNY_DB,
},
listPerPage: env.LIST_PER_PAGE,
};
module.exports = config;
./services/solarData.js
const db = require('./db');
const helper = require('../helper');
const config = require('../config');
async function getMultiple(page = 1){
const offset = helper.getOffset(page, config.listPerPage);
const rows = await db.query(
`SELECT * FROM DTP LIMIT ?,?`, [offset, config.listPerPage]
);
const data = helper.emptyOrRows(rows);
const meta = {page};
return {
data,
meta
}
}
module.exports.getMultiple = getMultiple;
./services/db.js
const mysql = require('mysql2/promise');
const config = require('../config');
async function query(sql, params) {
const connection = await mysql.createConnection(config.db);
const [results, ] = await connection.execute(sql, params);
return results;
}
module.exports = {
query
}
I've left out the ./helper.js
Everything runs fine until I direct the webpage to /solarData. At that point I get the Debug Console (vscode) mentioned up-front
Searching seems to point at a mysql2 shortcoming/bug but not at a practical solution
If you respond, please describe the 'bind' mechanism, as I'm not sure what's going on.
Hope I've put enough info in. Please ask if I need to add anything else.
The error says
Bind parameters must not contain undefined.
It means that in the file ./services/solarData.js on the line
const rows = await db.query(
`SELECT * FROM DTP LIMIT ?,?`, [offset, config.listPerPage]
);
Some of the 2 variables is undefined, you need to check offset and config.listPerPage to be defined.
Just use
console.log('offset: ' + offset)
console.log('listPerPage: ' + config.listPerPage)
and you will find out what is undefined in your case

I have a problem validating on update (express)

I'm trying to create a validator that will display an error message when a user tries to update a column that doesn't exist in the database schema. I'm using PostgreSQL. When I send a request with the correct allowed updates it returns an error: 'Invalid updates' What am I missing?
const updateQuestion = async (req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ['title', 'text, questionCateg']
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(400).send({
error: 'Invalid updates'
})
}
try {
const {
id
} = req.params;
const {
title,
text,
questionCateg
} = req.body
const updateQuestion = await pool.query("UPDATE Questions SET title = $1, text = $2, questionCateg = $3 WHERE id =$4",
[title, text, questionCateg, id]);
console.log(updateQuestion)
res.json('Question updated')
} catch (e) {
res.status(400).send()
}
}
Route:
router.patch('/questions/:id', updateQuestion)
Thanks in advance!
What do you see when you console.log(req.body) ? you should concentrate on that updates array.
You can use body-parser in your app.js or express.json() middleware
This way you can succesfully receive your items that you are sending to your backend.
You can send the updates in post request body with the key updates. Then you can parse it like req.body.updates (updates is an array)
You can use body parser like this
app.use(bodyParser.urlencoded({
extended: true
}));
or app.use(express.json())
you can see further information in this post express.json() and express.urlencoded()

Axios post request failing with a 404

I'm using Axios to query an endpoint in my backend. When I try and do this, I get a 404 not found. If I copy/paste the uri it gives in the error from the console and try and access it directly in the browser it connects fine and does not give me an error (instead giving me an empty object which is expected).
Below is my Axios code
axios.post("/api/myEndpoint", { id: this.userID })
.then((response) => {
this.property = response.data.property;
})
.catch((errors) => {
console.log(errors);
router.push("/");
});
Below is the route definition in my backend
const myEndpointRoute = require('../api/myEndpoint.js')();
exprApp.use('/api/myEndpoint', myEndpointRoute);
For reference, the uri is 'http://localhost:3000/api/myEndpoint'. I can access this uri completely fine in the browser but Axios returns a 404 as described above. It is for this reason that I'm confident this is an issue in the frontend, however I have set up this Axios request in the same way as the many others I have and they all work fine.
Edit: here's the rest of the backend
myEndpoint.js
module.exports = function() {
const express = require('express'), router = express.Router();
const authMiddleware = require('../loaders/authMiddleware.js')();
router.get('/', authMiddleware, async function(req, res) {
const id = req.body.id;
const property = await require('../services/myEndpointService.js')
(id).catch((e) => { console.log(e) });
res.send({ property: property });
});
return router;
};
myEndpointService.js
module.exports = async function(id) {
const results = await require('../models/getMyEndpointProperty')(id);
return results;
};
getMyEndpointProperty
module.exports = async function(id) {
const pool = require('../loaders/pool.js')();
const res = await pool.query(`SELECT * FROM myTable WHERE id = ${id};`);
return res.rows;
};
myEndpoint.js defines only a GET method but your axios call sends a POST in the frontend. Try changing (or adding) the express route:
// notice the `.post`
router.post('/', authMiddleware, async function(req, res) {
...
})
It worked when you manually tested it in the browser for this reason as well, since the browser sent a GET request.

Sending state for an Axios POST and data not showing in req.body

I'm using React and want to make a POST request using Axios. I'm trying to send form data to my Node backend.
I am trying to send an object in the POST request which is the state holding all of the user's inputs to a form.
React
const [formDetails, setFormDetails] = useState({})
const handleFormChange = (evt) => setFormDetails({ ...formDetails, [evt.target.name]: evt.target.value })
const sendInvoice = async (formDetails) => {
const response = await axios.post('/api/new_invoice', formDetails)
console.log(response)
}
Node route
module.exports = (app) => {
// Create a new invoice
app.post('/api/new_invoice', async (req, res) => {
console.log('making a new invoice...')
try {
console.log(req.body)
res.send(req.body)
} catch (err) {
console.log(err)
res.status(400)
res.send({ error: err })
return
}
})
}
This is what I get back:
When I look at the req.body for the response it is an empty object even though I can see that state is there when sending the form.
I also tried hardcoding an object and that will show the data on the req.body.
For example if I change the request to
const response = await axios.post('/api/new_invoice', {formData: 'this is form data'})
Then I am able to see formData: 'this is form data' in the req.body
You need to stringify the formData, In your sendInvoice function,
Also can you share the sample request body from postman of you have tested API there
let body= JSON.stringify(formData)
const config = {
headers: {
'Content-Type': 'application/JSON'
}
};
const res = await axios.post('/api/v1/new_invoice', body, config);
To handle an incoming JSON object from HTTP POST Request, you need to write the following code -
var express = require('express');
var app=express();
app.use(express.urlencoded()); // To parse URL-encoded bodies
app.use(express.json()); //To parse JSON bodies
// Note: (*applicable for Express 4.16+ )

Append objects to a json file

I have a task to implement a pseudo cart page and when I click on checkout i want to send a request to a json file "ordersTest.json" with a following structure:
{ "orders": [] }. So when a post request is sent i have to put the data in that orders array in the json. I am completely new to Nodejs and express. This is my first project on it and i came up with a very simple server.
const express = require('express')
const path = require('path')
const fs = require('fs')
const url = require('url')
const bodyParser = require('body-parser')
const app = express()
const ordersJson = require('./public/ordersTest.json');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.post('/api/orders', (req, res) => {
let body = req.body;
console.log(body);
fs.appendFile('./public/ordersTest.json', JSON.stringify(body), err => {
if (err) console.log(err);
})
})
But this thing only appends it to the end of the file. I need to put it inside this orders array
This is my ajax passing an example object in the body of the post:
$(".btn-checkout").on('click', function() {
let date = new Date();
$.ajax({
method : "POST",
url: "/api/orders",
data : {a: "abc"},//{ order: "order",date: date.toDateString(), order: JSON.stringify(cart)},
success : function(success){
console.log(success,'success');
},
error : function(err) {
console.log(err);
}
});
clearCart();
displayClearedCart();
});
You need to parse the JSON file and then treat it like an object. Once you are done with it, convert it to JSON again and overwrite your file. like this
app.post('/api/orders', (req, res) => {
let body = req.body;
var ordersTest = require('./public/ordersTest.json');
ordersTest.orders.push(body);
fs.writeFile('./public/ordersTest.json', JSON.stringify(ordersTest), function(err) {
if (err) res.sendStatus(500)
res.sendStatus(200);
});
})
Not tested, please fix typo error if any.

Categories