How to send data to Stripe nodejs express backend - express

I tried integrating Stripe into my React app using the official doc at https://stripe.com/docs/recipes/elements-react. If you could go through this doc, you'll find out they're using a static value as amount (2000).
// server.js
const app = require("express")();
const stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
app.use(require("body-parser").text());
app.post("/charge", async (req, res) => {
try {
let {status} = await stripe.charges.create({
amount: 2000,
currency: "usd",
description: "An example charge",
source: req.body
});
res.json({status});
} catch (err) {
res.status(500).end();
}
});
The post API from frontend using fetch is:
async submit(ev) {
let {token} = await this.props.stripe.createToken({name: "Name"});
let response = await fetch("/charge", {
method: "POST",
headers: {"Content-Type": "text/plain"},
body: token.id
});
if (response.ok) console.log("Purchase Complete!")
}
Here, they're sending the token ID and referencing it in the backend as source:req.body.
Now I have tried to send amount from the frontend through the POST request as follows:
body:{
amount: 2000,
tokenId: token.Id
}
and then referencing it in backend as
...
amount: req.body.amount,
source: req.body.tokenid
...
It doesn't work. And consoling both returns undefined
I have tried many things like removing content-type header and pretty little things. Someone pointed out that I should change content-type to application/json and I've thought of setting
app.use(require("body-parser").text()) to app.use(require("body-parser").json()) but decided to consult you guys first.

If I understand you correctly, you want to post a json from client to express server. If so:
Client
fetch({
method: 'POST',
body: JSON.stringify({
amount: 2000,
tokenId: token.Id
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
Server
const app = express();
// if express >= 4
app.use(express.json());
app.post("/charge", async (req, res) => {
console.log(req.body);
});
Any by the way tokenId !== tokenid (in req.body.tokenid)

Related

Spotify returning 200 on token endpoint, but response data is encoded

I'm working through this tutorial on creating an app that uses the Spotify API. Everything was going great until I got to the callback portion of authenticating using the authentication code flow.
(I do have my callback URL registered in my Spotify app.)
As far as I can tell, my code matches the callback route that this tutorial and others use. Significantly, the http library is axios. Here's the callback method:
app.get("/callback", (req, res) => {
const code = req.query.code || null;
const usp = new URLSearchParams({
code: code,
redirect_uri: REDIRECT_URI,
grant_type: "authorization_code",
});
axios({
method: "post",
url: "https://accounts.spotify.com/api/token",
data: usp,
headers: {
"content-type": "application/x-www-form-urlencoded",
Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64")}`,
},
})
.then(response => {
console.log(response.status); // logs 200
console.log(response.data); // logs encoded strings
if (response.status === 200) {
res.send(JSON.stringify(response.data))
} else {
res.send(response);
}
})
.catch((error) => {
res.send(error);
});
Though the response code is 200, here's a sample of what is getting returned in response.data: "\u001f�\b\u0000\u0000\u0000\u0000\u0000\u0000\u0003E�˒�0\u0000Ee�uS\u0015��\u000e�(\b\u0012h\u0005tC%\u0010\u0014T\u001e�����0��^޳:���p\u0014Ѻ\u000e��Is�7�:��\u0015l��ᑰ�g�����\u0"
It looks like it's encoded, but I don't know how (I tried base-64 unencoding) or why it isn't just coming back as regular JSON. This isn't just preventing me logging it to the console - I also can't access the fields I expect there to be in the response body, like access_token. Is there some argument I can pass to axios to say 'this should be json?'
Interestingly, if I use the npm 'request' package instead of axios, and pass the 'json: true' argument to it, I'm getting a valid token that I can print out and view as a regular old string. Below is code that works. But I'd really like to understand why my axios method doesn't.
app.get('/callback', function(req, res) {
// your application requests refresh and access tokens
// after checking the state parameter
const code = req.query.code || null;
const state = req.query.state || null;
const storedState = req.cookies ? req.cookies[stateKey] : null;
res.clearCookie(stateKey);
const authOptions = {
url: 'https://accounts.spotify.com/api/token',
form: {
code: code,
redirect_uri: REDIRECT_URI,
grant_type: 'authorization_code',
},
headers: {
Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64')}`,
},
json: true,
};
request.post(authOptions, function (error, response, body) {
if (!error && response.statusCode === 200) {
const access_token = body.access_token;
const refresh_token = body.refresh_token;
var options = {
url: 'https://api.spotify.com/v1/me',
headers: { Authorization: 'Bearer ' + access_token },
json: true,
};
// use the access token to access the Spotify Web API
request.get(options, function(error, response, body) {
console.log(body);
});
// we can also pass the token to the browser to make requests from there
res.redirect('/#' + querystring.stringify({
access_token: access_token,
refresh_token: refresh_token,
}));
} else {
res.redirect(`/#${querystring.stringify({ error: 'invalid_token' })}`);
}
});
});
You need to add Accept-Encoding with application/json in axios.post header.
The default of it is gzip
headers: {
"content-type": "application/x-www-form-urlencoded",
'Accept-Encoding': 'application/json'
Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64")}`,
}

req.body is unidentified in express api

I am implementing stripe payment in my react native app and created express api to get clientSecret Intent. So I want to make payment of the amount which I send from my api to api. But in api, I am getting nothing in the request body.
This is how I am calling my Apis
let data={totalAmount:amount, name:'XYZ_Name'}
fetch('http://10.0.2.2:3500/create-payment-intent', {
method: 'POST',
headers: { "Content-Type": "application/json" },
// "Content-Type" : "application/json",
body:data,
})
And this is my express api;
const app = express();
app.use(express.json());
app.use(
express.urlencoded({
extended: true,
})
);
app.post('/create-payment-intent', async (req,res)=>{
console.log('api Data',req.body.amount);
const paymentIntent = await stripe.paymentIntents.create({
amount:5000, //$50
currency:'gbp',
});
res.send({
clientSecret: paymentIntent.client_secret,
paymentIntent,
})
})
app.listen(3500,()=>{console.log('API Running!')});
I see two issues with the frontend code you shared.
First, you should replace totalAmount: amount by amount: amount, since the backend code is using req.body.amount.
Second, you can't directly send a JavaScript object using fetch, you need to convert it into a string with JSON.stringify(data).
With these two fixes, your frontend code should look like this:
let data= { amount: amount, name: 'XYZ_Name' };
fetch('http://10.0.2.2:3500/create-payment-intent', {
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
})
Note that I wouldn't recommend to pass the amount from the frontend to the backend, since a malicious user could directly change the amount in their browser.
Your data must be stringified
let data = { totalAmount:amount, name:'XYZ_Name' }
fetch('http://10.0.2.2:3500/create-payment-intent', {
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
})

Access post body without bodyparser

I am trying to send a bas64 encoded image to my express server and parse it there to save it to disk. Id like to implement this with a simple http post request but couldn't get it to work. My first implementation utilized a websocket server and worked well:
Client:
const object = JSON.stringify({
action: "add_image",
data: dataUrl,
})
ws.send(object)
Server:
ws.on("message", (message) => {
const req = JSON.parse(message);
fs.writeFile(
"path/to/file.png",
data.split(";base64,").pop(),
{ encoding: "base64" },
(err) => err && console.log(err)
)
}
This is my trying to get the same result with an http request.
Client:
const object = JSON.stringify({
action: "add_image",
data: dataUrl,
})
fetch("http://localhost:3001/add_image", {
method: "POST",
headers: new Headers({
Origin: window.origin,
Accept: "image/png",
"Content-Type": "image/png",
}),
mode: "cors",
body: object,
})
Server:
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.post("/add_image", function (req, res) {
console.log(req.body);
});
Unfortunately, req.body always logs an empty object.
I am not quite sure what I am lacking. Any help would be greatly appreciated.
I found the answer in this article. I needed to combine all individual chunks of the request and then use the data once the process is complete.
app.post("/add_image", function (req, res) {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
console.log(JSON.parse(body));
res.end('ok');
});
});

Is there a limit in the body of a request to an api in React native?Because i cant send large base64 to server

It says me syntax error: JSON Parse error. unrecognized token '<'
Iam using Fetch to do the request.It let me send short base64 strings i tried so what can i do?
This is my call to the api:
export function uploadPost(post) {
let data = {
body: post.body,
picture: post.picture,
type: post.type,
user: {
_id: post.user._id,
name: post.user.name,
picture: post.user.picture
}
}
var headers = {
'Content-Type': 'application/json',
'Access-Control-Origin': '*'
}
return fetch(URL + "/uploadPost", {
method: "post",
headers: headers,
body: JSON.stringify(data)
})
.then(response => Promise.resolve(response.json()))
.catch(err => {
return Promise.reject(err);
})
}
I finally solved it. The problem was that the response was returning a 413 status and I found out that means payload too large. So I added to my node js express server this lines:
var app = express();
//after
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));

Express CORS response

I am using express to return an api response retrieved via a request call.
router.post('/', function(req, res){
var options = {
...
}
rp(options)
.then(function (parsedBody) {
console.log(parsedBody);
res.json(parsedBody)
})
The console log displays the expected payload, also when I use Postman I also see the expected payload.
When though my client app gets the response it is:
Response {type: "cors", url: "http://localhost:3001/api/", redirected: false, status: 200, ok: true, …}
Ive tried adding CORS middleware:
app.use(function(request, response, next) {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers",
"Origin, X-Rquested-With, Content-Type, Accept");
next();
});
My client is a very simple react app using fetch:
fetch('http://localhost:3001/api/', {
method: 'POST',
dataType: 'JSON',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: data,
}).then((response) => {
console.log(response);
}).catch((response) => {
console.log('Error');
});
My react app is localhost:3000 and the express api localhost:3001, the expected payload is a very simple object...
{
athlete: {
firstname: "Matt"
...
}
}
How can I just forward on the api request response to the clients fetch success method?
The problem is not CORS related, the response within the react app needed parsing as json:
.then((response) => {
console.log(response.json());
})