Why is frontend receiving an empty object from express server? - javascript

Trying to figure out how to implement this request and response scenario with javascript's fetch() and an express server.
here's the server:
var express = require('express'),
stripeConnect = require('./routes/connect'),
cors = require('cors'),
bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cors());
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
app.use('/connect', connect);
app.listen(process.env.PORT || 5000);
here's routes/connect:
const express = require('express');
const router = express.Router();
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.cert({
projectId: process.env.projectId,
clientEmail: process.env.clientEmail,
privateKey: process.env.privateKey.replace(/\\n/g, '\n'),
clientId: process.env.clientId
}),
databaseURL: process.env.databaseURL
});
const STRIPE_SK = 'sk_test_KEY';
const stripe = require('stripe')(STRIPE_SK);
// #route POST /stripeConnect/link
// #desc save stripe user account id to their firebase profile
// #access public
router.post('/link', (req, res) => {
console.log('\nLINK-REQUEST-BODY => ');
console.log(req.body);
return admin
.firestore()
.collection('users')
.doc(req.body.docId)
.update({ stripeId: 'test_Id' })
.then((success) => {
console.log('Firestore Update: Success');
res.json({ msg: 'Stripe account ID added to Slide profile.' });
})
.catch((err) => {
console.log('Firestore Update: Fail, Error: ' + err.message);
res.json({ msg });
});
});
module.exports = router;
here's the fetch POST:
function submit() {
$("#progress-label").text("Working...")
const request = {
method: "POST",
body: JSON.stringify({
docId: $('#id').val(),
stripeId: USER_ID
}),
mode: 'cors',
headers: { 'Content-Type': 'application/json'}
}
fetch(SERVER_URL + "/link", request).then(res => {
console.log("res => " + res)
console.log("res.json() => "+ res.json())
console.log("JSON.stringify(res.json()) => "+ JSON.stringify(res.json()))
console.log("res.data => " + res.data)
console.log("res.msg" => + res.msg
}).catch(err => {
document.getElementById("label").innerHTML = res.json()
})
}
The express server logs Firebase Update Success
the front end logs:
res => [object Response]
res.json() => [object Promise]
JSON.stringify(res.json()) => {}
res.data => undefined
res.msg => undefined
Just trying to figure out how to properly get this response from express. Not sure what all of these log-symptoms are telling me. just figured id log all the different ways I could think of handling the response object.
What do I need to do to get the response data?

Your .then() function is just a promise because your receiving it as soon as you get the headers from the request, you need to send the response back (res.send()) in the .then() of the res.json() because it is also a promise. so that modify your routes/connect as per below.
router.post('/link', (req, res) => {
console.log('\nLINK-REQUEST-BODY => ');
console.log(req.body);
return admin
.firestore()
.collection('users')
.doc(req.body.docId)
.update({ stripeId: 'test_Id' })
.then((success) => {
console.log('Firestore Update: Success');
res.json().then(data => ({
data: data,
status: response.status
})
).then(res => {
console.log(res.status, res.data)
})
.catch((err) => {
console.log('Firestore Update: Fail, Error: ' + err.message);
res.json({ msg });
});
});

Related

CORS errors after deployment to render, worked fine locally

like the title says, here is my server file, I have tried every solution I could find on google yet I am still getting CORS errors. specifically XHROPTIONShttps://slug-panel-api.onrender.com/login
server.js:
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser')
const mongoose = require('mongoose')
const userSchema = require('../../SlugAPI/Schemas/SlugSchemas')
const divisionSchema = require('../src/SlugSchemas/DivisionSchemas/DivisionSchema')
const subDivisionSchema = require('../src/SlugSchemas/DivisionSchemas/SubDivisionSchema')
const teamSchema = require('../src/SlugSchemas/DivisionSchemas/TeamSchema')
const divisionMemberSchema = require('../src/SlugSchemas/DivisionSchemas/DivisionMemberSchema')
let CryptoJS = require('crypto-js')
const PORT = process.env.PORT || 8080;
const app = express();
app.use(cors({
origin: "https://slug-panel.onrender.com",
headers: {
"Access-Control-Allow-Origin": "https://slug-panel.onrender.com",
"Access-Control-Allow-Credentials": true
},
}));
mongoose.set("debug")
const usar_db = mongoose.createConnection("mongodb:/<username>:<password>#slug-db:27017/usarAdmin?authSource=admin");
const User = usar_db.model('User', userSchema)
const Division = usar_db.model('Division', divisionSchema)
const SubDivision = usar_db.model('SubDivision', subDivisionSchema)
const Team = usar_db.model('Team', teamSchema)
const DivisionMember = usar_db.model('Division_Member', divisionMemberSchema)
function generateUserRegistrationKey(username, discord_id, rank, authentication_level) {
let key = username + '/' + discord_id.toString() + '/' + rank + '/' + authentication_level
const ciphertext = CryptoJS.AES.encrypt(key, 'secret').toString()
return ciphertext
}
function decryptUserRegistrationKey(key) {
const bytes = CryptoJS.AES.decrypt(key, 'secret')
const originalText = bytes.toString(CryptoJS.enc.Utf8)
return originalText
}
app.post('/login', bodyParser.json(), async (req, res, next) => {
const user = req.body.username
let pw = req.body.password
pw = CryptoJS.SHA256(pw)
let exists = await User.findOne({username: user})
if (exists) {
if (pw.toString() === exists['password']) {
res.send({
token: 'test123'
})
} else {
res.send({
error: 'passwordNotFound'
})
}
} else {
res.send({
error: 'userNotFound'
})
}
});
app.post('/generate', bodyParser.json(), async function (req, res, next) {
let username = req.body.username
let discord_id = req.body.discord_id
let rank = req.body.rank
let authentication_level = req.body.authentication_level
let exists = await User.exists({discord_id: discord_id})
let regKey = generateUserRegistrationKey(username, discord_id, rank, authentication_level)
const newUser = User({
username: username,
discord_id: discord_id,
rank: rank,
regKey: regKey,
authentication_level: authentication_level,
})
if (!exists) {
newUser.save()
.then(r => console.log("User " + username + " added to db"))
res.send({regKey: regKey})
}
})
app.post('/register', bodyParser.json(), async function (req, res, next) {
let key = req.body.regKey
let pw = CryptoJS.SHA256(req.body.password).toString()
let decryptedKey = decryptUserRegistrationKey(key).split('/')
let exists = await User.find({regKey: key}, function(err, docs) {
if (err) {
console.log(err)
} else {
console.log('Result: ', docs)
console.log(pw)
}
}).clone()
if (!exists) {
res.send({user: null})
} else {
res.send(JSON.stringify(exists))
}
await User.findOneAndUpdate({regKey: key}, { is_registered: true, password: pw, authentication_level: decryptedKey[decryptedKey.length - 1]})
})
app.post('/createDivision', bodyParser.json(), async function (req, res, next) {
let div_name = req.body.division_name
let div_id = req.body.division_id
let exists = await Division.findOne({division_name: div_name}, function (err, docs) {
if (err) {
console.log(err)
} else {
console.log(docs)
}
}).clone()
let idexists = await Division.findOne({division_id: div_id}, function (err, docs) {
if (err) {
console.log(err)
} else {
console.log(docs)
}
}).clone()
if (!exists || !idexists) {
const newDivision = new Division({
division_name: div_name,
division_id: div_id
})
newDivision.save()
.then(() => console.log('Division ' + div_name + ' has been added to the db'))
res.send(JSON.stringify(newDivision))
} else {
res.send({errorcode: 420})
}
})
app.post('/createSubDivision/:divid', bodyParser.json(), async function (req, res, next) {
const division = req.params['divid']
const sub_name = req.body.subdivision_name
const sub_id = req.body.subdivision_id
let exists = await Division.findOne({division_id: division}, function (err, docs) {
if (err) {
console.log(err)
} else {
console.log(docs)
}
}).clone()
if (exists) {
let subdivid_exists = await Division.findOne({
division_id: division,
subdivisions: {
$elemMatch: {subdivision_id: sub_id}
}
})
let subdiv_exists = await Division.findOne({
division_id: division,
subdivisions: {
$elemMatch: {subdivision_name: sub_name}
}
})
if (!subdivid_exists || !subdiv_exists) {
const subDiv = new SubDivision({
subdivision_name: sub_name,
subdivision_id: sub_id,
})
await Division.findOneAndUpdate({division_id: division}, { $push: {subdivisions: subDiv}})
console.log('subdivision ' + sub_name + ' added to: ' + exists.division_name)
res.send(JSON.stringify(subDiv))
} else {
res.send({division:'exists'})
}
}
})
app.listen(PORT, () => console.log('API is running on ' + PORT));
Tried every solution I could find both on random google websites and on stackoverflow. as stated previously it worked fine on the development server hosted locally.
for reference, here is how I am using fetch throughout the frontend
async function loginUser(credentials) {
return fetch('https://slugga-api.onrender.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'true'
},
body: JSON.stringify(credentials)
})
.then(data => data.json())
}
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://slugga-api.onrender.com/login. (Reason: CORS request did not succeed). Status code: (null).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://slugga-api.onrender.com/login. (Reason: CORS request did not succeed). Status code: (null).
Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource. asyncToGenerator.js:6:4
Babel 6
c Login.js:20
React 11
bind_applyFunctionN self-hosted:1683
Wt self-hosted:1640
React 3
forEach self-hosted:4909
React 2
<anonymous> index.js:7
<anonymous> index.js:17
<anonymous> index.js:17
You're misusing those CORS headers, both on the client side and on the server side. You should familiarise better with CORS and with the API of Express.js's CORS middleware.
Client side
The Access-Control-Allow-Origin header is a response header; including it in a request makes no sense.
async function loginUser(credentials) {
return fetch('https://slugga-api.onrender.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'true' // incorrect
},
body: JSON.stringify(credentials)
})
.then(data => data.json())
}
Server side
The headers property of your CORS config corresponds to request headers that you wish to allow, but what you've listed are response headers.
app.use(cors({
origin: "https://slug-panel.onrender.com",
headers: {
"Access-Control-Allow-Origin": "https://slug-panel.onrender.com", // incorrect
"Access-Control-Allow-Credentials": true // incorrect
},
}));
Instead, you most likely want something like
app.use(cors({
origin: "https://slug-panel.onrender.com",
headers: ["Content-Type"],
credentials: true,
}));
Fixed the issue by changing the CORS initialization in server.js
const app = express();
app.use(cors({
origin: "https://slug-panel.onrender.com"
}
))
app.options('*', cors())

JWT token returning undefined in MERN application

I am using JWT token for authentication in my MERN app. when i click on this endpoint "http://127.0.0.1:1000/api/v1/users/login" in postman to login a user and this endpoint "http://127.0.0.1:1000/api/v1/users/verify" to verify a user's token, the token is returned. However, when i do the same operation in my react frontend app, the token returns undefined. Please what am i doing wrong? Here is my React code. P.S the token is stored in the cookies.
function Welcome() {
const [user, setUser] = useState("");
const sendRequest = async () => {
const res = await axios
.get("http://127.0.0.1:1000/api/v1/users/verify", {
withCredentials: true,
})
.catch((err) => console.log(err));
const data = await res.data;
console.log("RESPONSE", data);
return data;
};
React.useEffect(() => {
sendRequest().then((data) => console.log(data));
}, []);
console.log(user);
return <div>Welcome</div>;
}
Here is the Verify token code in my express app
exports.verifyToken = async (req, res, next) => {
const cookies = await req.headers.cookie;
const token = cookies.split("=")[1];
if (!token) {
res.status(404).json({ message: "no token found" });
}
jwt.verify(String(token), process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(400).json({message: "Invalid token" });
}
req.id = user.id;
});
next();
};
User cookie parser
const express = require("express");
const app = express();
const cookieParser = require("cookie-parser");
app.use(express.json());
app.use(cookieParser());
app.get("/", (req, res) => {
res.setHeader("Set-Cookie", "name=langesh;SameSite=None;");
res.send("hello");
});
app.get("/get-cookie", (req, res) => {
res.send(req.cookies);
});
app.listen(9000);
output
{name : "langesh"}
I personally don't have much experience with axios, I prefer fetch() method, it works perfectly.
That said, I think this issue could arise because token isn't identified in the request. Try adding headers: { Authorization: `Bearer ${token}`} to your get method and see if it is fixed.
Your code should look like :
axios.get("http://127.0.0.1:1000/api/v1/users/verify", {
headers: {
Authorization: `Bearer ${token}`
},
withCredentials: true,
})

POST API will not get save

I did a POST request, and I got a signal via console.log, but my array doesn't get updated. What am I missing?
CLIENT:
const handleClick = () => {
console.log("i was clicked")
fetch("http://localhost:5000/", {
method: "post",
headers: {'Accept': 'application/json',"Content-Type": "application/json"},
body: JSON.stringify(testPost),
}).then((res) => res.json())
.then(data =>{console.log("success", data)})
.catch((err) =>{console.log("rejected", err)})
};
SERVER:
let data = {
'skills': ["breathing ", "pooping"],
'awards': 2
}
app.get("/", (req, res) => {
res.json(data);
});
app.post("/", (req, res) => {
const {body} = req;
res.json(data)
console.log(body)
console.log(data)
});
I use express, cors, body-parser on the server. On the client nothing special.
my expecation: { skills: [ 'breathing ', 'pooping', 'eating' ], awards: 2 }
my results: { skills: [ 'breathing ', 'pooping' ], awards: 2 }
First, I don't know what kind of data you send to your endpoint.
So I think you send the whole object.
let data = {
'skills': ["breathing ", "pooping"],
'awards': 2
}
// ...
app.post("/", (req, res) => {
const {body} = req;
data = body // this is what you are missing
res.json(data)
console.log(body)
console.log(data)
});
What you need is to update your data object on your post request. I am assuming from your comment that your request body is like this {skills: ["eating"]}. So you may update your post api like this.
let data = {
'skills': ["breathing ", "pooping"],
'awards': 2
}
app.get("/", (req, res) => {
res.json(data);
});
app.post("/", (req, res) => {
// update skills array
data.skills = [...data.skills, ...req.body.skills];
res.json(data)
console.log(body)
console.log(data)
});
this should provide your expected result.

Getting either an 500 internal server error or invalid value for stripe.confirmCardPayment

I'm trying to make a payment component to my react app. This is my first time using stripe. I've tried to follow a tutorial, and I have done exactly the same thing as in the tutorial, but still getting an internal server error or invalid value for stripe.confirmCardPayment (see image below) when posting the request with axios. Hopefully someone can guide me onto the right track with this.
CheckoutForm.js - HandleSubmit function
handleSubmit = async event => {
event.preventDefault();
const { stripe, elements } = this.props;
if (!stripe || !elements) {
return;
}
const card = elements.getElement(CardElement);
const { } = await axios.post("/api/stripe/charge", {
amount: 1000,
})
const paymentMethodReq = await stripe.createPaymentMethod({
type: 'card',
card: card,
billing_details: {
name: 'Daniel Olsen',
email: 'olsen.daniel04#gmail.com'
},
payment_method: {
card: card
}
})
console.log(paymentMethodReq)
axios.get('/api/stripe/charge').then(function(response) {
console.log(response)
return response.json();
}).then(function(responseJson) {
var clientSecret = responseJson.client_secret;
const confirm = await stripe.confirmCardPayment(clientSecret, {
payment_method: paymentMethodReq.paymentMethod
})
});
const result = await stripe.createToken(card);
if (result.error) {
console.log(result.error.message);
} else {
console.log(result.token);
}
};
Stripe.js
const stripe = require('stripe')('secret_key')
async function postCharge(req, res) {
try {
const { amount } = req.body
const charge = await stripe.paymentIntent.create({
amount: 2000,
currency: 'nok',
payment_method_types: ['card'],
})
if (!charge) throw new Error('charge unsuccessful')
res.status(200).json({
message: 'charge posted successfully',
charge
})
} catch (error) {
res.status(500).json({
message: error.message
})
}
}
module.exports = postCharge
server.js
const app = express()
const router = express.Router()
const port = 3000
app.post('/stripe/charge', postCharge)
router.all('*', (_, res) =>
res.json({ message: 'please make a POST request to /stripe/charge' })
)
app.use((_, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
)
next()
})
app.use(bodyParser.json())
app.use('/api', router)
app.use(express.static(path.join(__dirname, '../build')))
app.get('*', (_, res) => {
res.sendFile(path.resolve(__dirname, '../build/index.html'))
})
app.listen(port, () => console.log(`server running on port ${port}`))
Error:
After you create the payment intent you're sending back the entire "charge" [sic] object in the json:
res.status(200).json({
message: 'charge posted successfully',
charge
})
While I'd suggest changing this to only send back the client_secret, the way you have it now the client needs to retrieve responseJson.charge.client_secret. You're missing that charge layer.

Passing token to another request in Node.js

In first request I'm asking external server to provide a token. And I'm getting it. Then I would like to use it in another request. All is done in express.js. What is the best solution to provide it to the another request?
It looks like this:
const express = require('express');
const axios = require('axios');
const config = require('./config');
const app = express();
axios.post('URL1', {
email: config.email,
password: config.password,
})
.then(function(response) {
console.log(response.data.token); //here I' getting the token
})
.catch(function(error) {
console.log(error);
});
const headers = { headers: { 'Authorization': 'Token ' + token } }; //here I would like to use (for the use of a second request)
axios.get('URL2', headers)
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
const PORT = process.env.PORT || 5000;
app.listen(PORT);
Of course I cannot just assign it to the variable. Thank you for helping!
You can call it in another function just as shown below.
const express = require('express');
const axios = require('axios');
const config = require('./config');
const app = express();
axios.post('URL1', {
email: config.email,
password: config.password,
}).then((response) => {
// calling function here
return handleToken(response.data.token);
console.log(response.data.token); //here I' getting the token
}).catch((error) => {
console.log(error);
});
//second request will be handled here
const handleToken = (token) => {
const headers = { headers: { 'Authorization': 'Token ' + token } };
//here I would like to use (for the use of a second request)
axios.get('URL2', headers)
.then((response) => {
console.log(response);
}).catch((error) => {
console.log(error);
});
}
const PORT = process.env.PORT || 5000;
app.listen(PORT);
It's preferable if you write a separate function to avoid callback hell.
EDIT - ROUTE WITH ASYNC/AWAIT
app.get('/', async (req, res)=>{
try {
let result = await axios.post('URL1', { email: config.email, password: config.password });
let final = await handleToken(response.data.token);
// other operations here
console.log(result);
} catch (err) {
//handle error here
console.error(err);
}
})
//second request will be handled here
const handleToken = async (token) => {
try {
const headers = { headers: { 'Authorization': 'Token ' + token } };
let response = await axios.get('URL2', headers);
return response;
} catch (err) {
throw err;
}
}

Categories

Resources