Fetch method put with React.js and Node server - javascript

I want to update my data in my MySQL database. I have React front-end and I'm using node server as back-end. I am getting nothing with body when I try to update data with fetch put method. Why is that?
Why does "body" in fetch method with JSON.stringify(req.body) give me an empty object server-side?
React code(button click event):
handlePrioDown(a) {
sessionStorage["id"] = a["id"];
sessionStorage["priority"] = a["priority"];
fetch('http://localhost:3001/TeacherPri/'+a["id"], {
method: 'PUT',
body: JSON.stringify({priority: a["priority"]+1})
})
}
Node (server.js):
//CORS middleware
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
app.use( bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(allowCrossDomain)
app.use(express.json())
app.route("/TeacherPri/:id")
.put(controller.changePriority)
Node (controller.js):
changePriority: (req ,res) => {
let v = req.body;
let key = req.params.id;
console.log(JSON.stringify(v) + " ::::: id="+key)
CONN.query('UPDATE teacher SET priority=? WHERE id=?', [v.priority, key],
(err, results, fields) => {
if(err) {
console.log(err)
res.json(err)
} else {
console.log("Done")
res.statusCode = 204
res.send();
}
})
}
I'm excpecting that I get something like { priority: 4 } as req.body object on server side. I get empty object atm.

Related

Stripe & Node.js - "Cannot POST /create-checkout-session"

I'm trying to follow the Stripe Checkout subscription instructions:
https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=checkout
When I submit the form, over localhost I get "Cannot POST /create-checkout-session" (404 in network tab), and if I run from my production server, it just opens /create-checkout-session as a new (blank) Vue page. I have tried changing the form action to https://mydomain.xyz/create-checkout-session, but it didn't work.
Subscribe.vue
<form action="/create-checkout-session" method="POST">
<input type="hidden" name="priceId" value="[removed for Stack Overflow]" />
<button type="submit">Checkout</button>
</form>
I don't know if something is interfering with the endpoint, so I've copied my entire app.js file:
app.js
let express = require('express'),
cors = require('cors'),
mongoose = require('mongoose'),
database = require('./database'),
bodyParser = require('body-parser');
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = require('stripe')('[removed for StackOverflow]');
//connect mongoDB
mongoose.Promise = global.Promise;
mongoose.connect(database.db, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log("Database connected")
},
error => {
console.log("Database couldn't be connected to: " + error);
}
)
const cryptoEndPoint = require('../backend/routes/crypto.route')
const app = express();
app.use(decodeIDToken);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cors())
//API
app.use('/api', cryptoEndPoint)
app.post("/create-checkout-session", async (req, res) => {
console.log("can't even get anything to console log, only get createError is not defined");
const { priceId } = req.body;
// Create new Checkout Session for the order
// Other optional params include:
// [billing_address_collection] - to display billing address details on the page
// [customer] - if you have an existing Stripe Customer ID
// [customer_email] - lets you prefill the email input in the form
// [automatic_tax] - to automatically calculate sales tax, VAT and GST in the checkout page
// For full details see https://stripe.com/docs/api/checkout/sessions/create
try {
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [
{
price: priceId,
// For metered billing, do not pass quantity
quantity: 1,
},
],
// {CHECKOUT_SESSION_ID} is a string literal; do not change it!
// the actual Session ID is returned in the query parameter when your customer
// is redirected to the success page.
success_url: 'https://mydomain.xyz/thankyou?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://mydomain.xyz/thankyou',
});
return res.redirect(303, session.url);
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
});
//create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port);
})
//Find 404
app.use((req, res, next) => {
next(createError(404));
})
//error handler
app.use(function (err, req, res, next) {
console.log(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
})
/**
* Decodes the JSON Web Token sent via the frontend app
* Makes the currentUser (firebase) data available on the body.
*/
async function decodeIDToken(req, res, next) {
if (req.headers?.authorization?.startsWith('Bearer ')) {
const idToken = req.headers.authorization.split('Bearer ')[1];
// console.log(idToken);
try {
const decodedToken = await admin.auth().verifyIdToken(idToken);
// console.log("one");
req['currentUser'] = decodedToken;
// console.log("two");
} catch (err) {
console.log("error: " + err);
}
}
next();
}
app.post("/webhook", async (req, res) => {
let data;
let eventType;
// Check if webhook signing is configured.
const webhookSecret = '[removed for Stack Overflow]'
if (webhookSecret) {
// Retrieve the event by verifying the signature using the raw body and secret.
let event;
let signature = req.headers["stripe-signature"];
try {
event = stripe.webhooks.constructEvent(
req.body,
signature,
webhookSecret
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`);
return res.sendStatus(400);
}
// Extract the object from the event.
data = event.data;
eventType = event.type;
} else {
// Webhook signing is recommended, but if the secret is not configured in `config.js`,
// retrieve the event data directly from the request body.
data = req.body.data;
eventType = req.body.type;
}
switch (eventType) {
case 'checkout.session.completed':
//...
break;
case 'invoice.paid':
//...
break;
case 'invoice.payment_failed':
//...
break;
default:
// Unhandled event type
}
res.sendStatus(200);
});
Does anyone know what is going wrong?
I added this to my app.js file, and it's working:
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
app.use(allowCrossDomain);

Express response manipulation to send string to client

I have the following app.js file for handle a specific endpoint:
const express = require('express');
const app = express();
app.use((req, res, next) => {
!process.env.HTTP_ACCESS_IP || res.setHeader('Access-Control-Allow-Origin', process.env.HTTP_ACCESS_IP);
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Authorization'
);
res.setHeader(
'Access-Control-Allow-Methods',
'GET, POST, PATCH, PUT, DELETE, OPTIONS',
);
next();
});
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));
app.post('/api/verificationstart', (req, res) => {
return res.status(400).send({ message: 'TEST' });
})
module.exports = app;
I my client side, I send HTTP REQUEST to the endpoint above, then code res.json().
async function fetchApi() {
return fetch('...', {
method: 'POST',
referrerPolicy: 'no-referrer',
});
}
async function verificationStartApi(data) {
const res = await fetchApi();
if (res._bodyText || res._bodyInit) {
return res.json();
} else {
return res;
}
}
The problem is that, from the res.json() I'd like to get a string object, not a JSON one. How could I do it? So that the result from res.json() would be "{ message: 'TEST' }".
Note that I want solution in backend. I can't touch client side.
I've been trying anything in backend using res.send() but nothing did the work:
res.send('"{ "message": "string" }"');
res.send('{ message: "test" }');
res.send('{ "message": "test" }');
So this is the ugliest answer:
return res.send('"{ \\"message\\": \\"string\\" }"');
You could use double JSON.stringify.
app.post('/api/verificationstart', (req, res) => {
// it will be res.send('"{\\"message\\":\\"TEST\\"}"')
res.send(JSON.stringify(JSON.stringify({ message: 'TEST' })))
})
Send a JSON valid string. Suppose this is your api.
app.post('/api/verificationstart', (req, res) => {
return res.status(400).send(JSON.stringify("{ message: 'TEST' }"));
})
res.send(JSON.stringify('{ "message": "test" }'));.
EDIT:
Get what you mean. enclose the Stringified JSON inside a string. Have a look at my update, tested it.

Reference error is not defined on application

When trying to submit data on a form, the webserver is giving me an error saying Reference error: Item is not defined, but based on my code, everything looks okay to me. Is there anything that stands out to you in my code that might cause this?
I was playing around with the Const, but I'm not sure if that's where the problem lies.
Here's my Javascript file:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
//specify where to find the schema
const Items = require('./models/item')
// connect and display the status
mongoose.connect('mongodb://localhost:27017/items', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => { console.log("connected"); })
.catch(() => { console.log("error connecting"); });
// use the following code on any request that matches the specified mount path
app.use((req, res, next) => {
console.log('This line is always called');
res.setHeader('Access-Control-Allow-Origin', '*'); //can connect from any host
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS'); //allowable methods
res.setHeader('Access-Control-Allow-Headers', 'Origin, Content-Type, Accept');
next();
});
app.get('/items', (req, res, next) => {
//call mongoose method find (MongoDB db.Items.find())
Items.find()
//if data is returned, send data as a response
.then(data => res.status(200).json(data))
//if error, send internal server error
.catch(err => {
console.log('Error: ${err}');
res.status(500).json(err);
});
});
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// serve incoming post requests to /items
app.post('/items', (req, res, next) => {
// create a new item variable and save request’s fields
const Items = new items ({
itemName: req.body.itemName,
servings: req.body.servings
});
//send the document to the database
Items.save()
//in case of success
.then(() => { console.log('Success');})
//if error
.catch(err => {console.log('Error:' + err);});
});
//to use this middleware in other parts of the application
module.exports=app;
app.post('/items', (req, res, next) => {
// Items already defined
const items = new Items({
itemName: req.body.itemName,
servings: req.body.servings
});
items.save()
//in case of success
.then(() => { console.log('Success');})
//if error
.catch(err => {console.log('Error:' + err);});
});
Items constant is already declared, and you trying to re-declare it

Having issues with javascript compiling

I have an application Javascript file that is showing an error in the console section of VS Studio Code, it keeps saying: app.js: The parser expected to find a '}' to match the '{' token here. and the console will not compile.
Based on my code, would you be able to tell me where I need to close in my braces? I think I might be confused.
Here is my app.js code:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
//specify where to find the schema
const Item = require('./models/item')
// connect and display the status
mongoose.connect('mongodb://localhost:27017/items', { useNewUrlParser: true })
.then(() => { console.log("connected"); })
.catch(() => { console.log("error connecting"); });
// use the following code on any request that matches the specified mount path
app.use((req, res, next) => {
console.log('This line is always called');
res.setHeader('Access-Control-Allow-Origin', '*'); //can connect from any host
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS'); //allowable methods
res.setHeader('Access-Control-Allow-Headers', 'Origin, Content-Type, Accept');
next();
});
app.get('/items', (req, res, next) => {
//call mongoose method find (MongoDB db.Students.find())
Item.find()
//if data is returned, send data as a response
.then(data => res.status(200).json(data))
//if error, send internal server error
.catch(err => {
console.log('Error: ${err}');
res.status(500).json(err);
});
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// serve incoming post requests to /items
app.post('/items', (req, res, next) => {
const items = req.body;
console.log(items.itemName + " " + items.servings);
//sent an acknowledgment back to caller
res.status(201).json('Post successful');
});
//to use this middleware in other parts of the application
module.exports=app;
Your app.get('/items' function is not closed. Try this.
app.get('/items', (req, res, next) => {
//call mongoose method find (MongoDB db.Students.find())
Item.find()
//if data is returned, send data as a response
.then(data => res.status(200).json(data))
//if error, send internal server error
.catch(err => {
console.log('Error: ${err}');
res.status(500).json(err);
});
});
But in the future, please just use an IDE of some sorts. Even just dumping your code into JSFiddle will highlight this for you.

Axios data is breaking the request

I have an express API and a ReactJs front-end. I try to make a POST call from my front-end directly to the local API.
For this I'm using axios.
The request is working fine when I set the parameters directly inside the query string but is always getting on timeout if I try to add the parameters through the data attribute of the axios.post() method.
Working
axios.post(`http://localhost:5001/site/authenticate?username=demo&password=demo`)
Not working
const payload = {
"username":"mh",
"password":"mh"
}
axios.post(`http://localhost:5001/site/authenticate`, payload)
My express server:
const express = require('express');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var cors = require('cors');
const app = express();
const port = process.env.API_PORT || 5001;
app.use(cors());
app.set('secret', process.env.API_SECRET);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(morgan('dev'));
app.use((req, res, next) => {
let data = '';
req.setEncoding('utf8');
req.on('data', (chunk) => {
data += chunk;
});
req.on('end', () => {
req.rawBody = data;
next();
});
});
// Allow CORS
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// SITE ROUTES -------------------
const siteRoutes = express.Router();
siteRoutes.post('/authenticate', function(req, res) {
console.log('auth');
getDocument(usersBucket, req.query.username)
.then((doc) => {
console.log("Authentification... TODO");
// return the information including token as JSON
res.json({
success: true,
status: 200,
token: token
});
})
.catch(() => {
res.status(401).json({ success: false, message: 'Authentification failed. User not found.' });
});
});
// route middleware to verify a token
siteRoutes.use(function(req, res, next) {
const token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('secret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.', status: 401 });
} else {
req.decoded = decoded;
next();
}
});
} else {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
siteRoutes.get('/', function(req, res) {
res.json({ message: 'Welcome!' });
});
app.use('/site', siteRoutes);
app.listen(port, () => {
logger.log(`Express server listening on port ${port}`);
});
Any idea? Thanks.
Update
I replaced my route just to see if I got in or not (without worrying about parameters):
siteRoutes.post('/authenticate', function(req, res) {
console.log("go in");
res.json({
success: true,
status: 200,
});
});
But my console.log is not showing hen I use the payload (it is when I do not).
You should access the payload data via request.body, not the request.query:
// SITE ROUTES -------------------
const siteRoutes = express.Router();
siteRoutes.post('/authenticate', function(req, res) {
console.log('auth');
getDocument(usersBucket, req.body.username) // <------- HERE
.then((doc) => {
console.log("Authentification... TODO");
// return the information including token as JSON
res.json({
success: true,
status: 200,
token: token
});
})
.catch(() => {
res.status(401).json({ success: false, message: 'Authentification failed. User not found.' });
});
});
request.query are the parameters passed in the URL, like:
protocol://hostname:port/path/to.route?query_param_0=value_0&query_param_1=value_1
on your express endpoint request.query will be:
{
query_param_0: value_0,
query_param_1: value_1
}
while sending the payload, with the second argument in axios.post(url, payload):
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
on your express endpoint request.body will be:
{
firstName: 'Fred',
lastName: 'Flintstone'
}
when you use app.use(bodyParser.json()); (and you do).
You are using “getDocument(usersBucket, req.query.username)”
This means you express route is expecting username as a request param. That’s why it’s working when you use “?username=xx”
Instead try to get it from json body of request.
“req.body.username”
Also you should consider validating the request body or param as required.

Categories