React Stripe Heroku - checkout payment not working anymore after deployment - node.js

I'm trying to implement stripe to my small e-commerce website developed in reactjs. To do so I've used the checkout component.
It works perfectly when i'm on localhost, but after i deploy the backend with heroku I receive this error message :
Apparently i didn't provide the API key but I feel like I did... I don't understand ...
Anyone ?
On the front end :
// Linking with the back end
const makePayment = (token) => {
const body = {
token: token,
product: product,
};
const headers = {
"Content-Type": "application/json",
};
return fetch(`https://serotonineneshop.herokuapp.com/payment`, {
method: "POST",
headers: headers,
body: JSON.stringify(body),
})
.then((response) => {
console.log("RESPONSE : ", response);
const { status } = response;
console.log("STATUS : ", status);
})
.catch((err) => console.log(err));
};
on the back-end :
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY)
app.post("/payment", (req, res) => {
const {
product,
token
} = req.body;
const idempotencyKey = uuidv4()
return stripe.customers.create({
email: token.email,
source: token.id
}).then(customer => {
stripe.charges.create({
amount: product.price * 100,
currency: "eur",
customer: customer.id,
receipt_email: token.email,
description: `purchase of ${product.name}`,
shipping: {
name: token.card.name,
phone: token.card.phone,
address: {
country: token.card.address_country,
postAddress: token.card.address,
zipCode: token.card.zipCode
}
}
}, {
idempotencyKey
})
.then(result = res.status(202).json(result))
.catch(err => console.log(err))
})
});

Related

Stripe integration in React and Node

Node code:
app.post("/create-payment-intent", async (req, res) => {
try {
const { items } = req.body;
console.log(items)
const paymentIntent = await stripe.paymentIntents.create({
currency: "gbp",
amount: items,
automatic_payment_methods: { enabled: true },
});
// Send publishable key and PaymentIntent details to client
res.send({
clientSecret: paymentIntent.client_secret,
});
React code:
useEffect(() => {
fetch("/create-payment-intent", {
method: "POST",
headers: {
"Content-Type" : "application/json"
},
body: JSON.stringify({items: [{ price: totalAmount }]}),
}).then(async (result) => {
var { clientSecret } = await result.json();
setClientSecret(clientSecret);
});
}, [totalAmount]);
Error: error
I do not understand why I cannot destructure items on the back end when it has been passed.
I have used the Stripe docs in order to attempt this: https://stripe.com/docs/payments/quickstart?locale=en-GB&lang=node

Stripe webhook host with node.js deployment

Is it possible to host stripe webhook with node.js deploy.
I've setup my stripe webhook with stripe checkout and It's ran successfully in localhost using stripe cli.
But I'm tried to take webhooks live.
const express = require("express");
const Stripe = require("stripe");
const { Order } = require("../models/Order");
require("dotenv").config();
const stripe = Stripe(`${process.env.STRIPE_SECRET}`);
const router = express.Router();
router.post("/create-checkout-session", async (req, res) => {
const customer = await stripe.customers.create({
metadata: {
userId: req.body.userId,
cart: JSON.stringify(req.body.products),
},
});
const line_items = req.body.products.map((item) => {
return {
price_data: {
currency: "usd",
product_data: {
name: item.title,
description: item.description,
metadata: {
id: item.id,
},
},
unit_amount: item.price * 100,
},
quantity: item.quantity,
};
});
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
shipping_address_collection: {
allowed_countries: ["BD", "US", "CA"],
},
shipping_options: [
{
shipping_rate_data: {
type: "fixed_amount",
fixed_amount: {
amount: 0,
currency: "usd",
},
display_name: "Free shipping",
// Delivers between 5-7 business days
delivery_estimate: {
minimum: {
unit: "business_day",
value: 5,
},
maximum: {
unit: "business_day",
value: 7,
},
},
},
},
{
shipping_rate_data: {
type: "fixed_amount",
fixed_amount: {
amount: 1500,
currency: "usd",
},
display_name: "Next day air",
// Delivers in exactly 1 business day
delivery_estimate: {
minimum: {
unit: "business_day",
value: 1,
},
maximum: {
unit: "business_day",
value: 1,
},
},
},
},
],
line_items,
mode: "payment",
customer: customer.id,
success_url: `https://nobab-3b3c4.web.app/checkout-success`,
cancel_url: `https://nobab-3b3c4.web.app/`,
});
// res.redirect(303, session.url);
res.send({ url: session.url });
});
// Create order function
const createOrder = async (customer, data) => {
const Items = JSON.parse(customer.metadata.cart);
const products = Items.map((item) => {
return {
productId: item.id,
quantity: item.quantity,
};
});
const newOrder = new Order({
userId: customer.metadata.userId,
customerId: data.customer,
paymentIntentId: data.payment_intent,
products,
subtotal: data.amount_subtotal,
total: data.amount_total,
shipping: data.customer_details,
payment_status: data.payment_status,
});
try {
const savedOrder = await newOrder.save();
console.log("Processed Order:", savedOrder);
} catch (err) {
console.log(err);
}
};
// Stripe webhoook
router.post(
"/webhook",
express.json({ type: "application/json" }),
async (req, res) => {
let data;
let eventType;
// Check if webhook signing is configured.
// let webhookSecret = `${process.env.STRIPE_WEB_HOOK}`;
let webhookSecret;
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: ${err}`);
return res.sendStatus(400);
}
// Extract the object from the event.
data = event.data.object;
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.object;
eventType = req.body.type;
}
// Handle the checkout.session.completed event
if (eventType === "checkout.session.completed") {
stripe.customers
.retrieve(data.customer)
.then(async (customer) => {
try {
// CREATE ORDER
createOrder(customer, data);
console.log("Ordered");
res.status(200).json({ message: 'Order created', data: data })
res.status(200).send("Order created")
} catch (err) {
console.log(typeof createOrder);
console.log(err);
}
})
.catch((err) => console.log(err.message));
}
res.status(200).end();
}
);
module.exports = router;
This code working fine and store user order in mongodb database, but i need to run this after my server deployment.
Thanks everyone
for help me
Yes it should be possible to host webhook with Node: Stripe Doc. It's a separated logic with your Checkout Creation endpoint, and you will need to test the webhook endpoint properly.

Axios Patch Request showing params as undefined in the backed

I want to update data in the server with a Axios Patch call and there seems to be some error in the code which i cant seem to figure out. Help me out please.
Node express API call in the backend:
router.patch('/up',async (req, res) => {
try{
const id = req.query.userid; // User objectid here.
console.log(req.body)
console.log(req.query.userid)
const result= User.findById(id, (error, foundUser) => {
if (foundUser) {
const { products } = foundUser;
const filteredproducts = products.filter((item) => {
return item._id!= req.body.body._id; //product array object id
});
while (foundUser.products.length > 0) {
foundUser.products.pop();
}
foundUser.products = filteredproducts;
foundUser.products.push({
brandname: req.body.brandname,
productname: req.body.productname,
quantity: req.body.quantity,
price: req.body.price,
description: req.body.description
});
foundUser.save();
}
else
{
console.log('User not found')
}
})
res.status(200).send("update successfull");
}
catch(err){
res.status(403).send('update unsuccessfull')
console.log(err)
}
})
Userschema in db:
const userschema = new mongoose.Schema({
username: {
type: String,
},
email: {
type: String,
required: true
},
place: {
type: String,
required: true
},
password: {
type: String,
required: true
},
products:[
{
brandname: {
type:String,
required:true
},
productname:{
type:String,
required:true
},
quantity:{
type:Number,
required:true
},
price:{
type:Number,
required:true
},
description:{
type:String,
required:true
}
}
]
,
tokens:
[{
token: {
type: String,
required: true
}
}
]
})
const User = mongoose.model('USER', userschema)
Front end API code
const updateproduct = async(req,res) => {
console.warn(values.brandname, values.productname,values.quantity, values.price,
values.description)
console.warn("userlogin is:,",userid) // User object id here.
const _id=id; // Product object id here
await axios.patch(`http://localhost:5000/up`,{
headers: {
'Content-type': 'application/json'
},
data: {brandname,productname,quantity,price,description,_id}, //getting the values of all the fields here. checked by console logging them.
params:{
'userid':userid
}
},
{ withCredentials: true })
.then((res) => {
console.log(res)
navigate('/listproduct')
})
.catch((err) => {
console.log(err)
})
}
Sorry if my code look really bad. I am new to React and node.
All i wanna do is edit the product details of a product by the product objectid and store it in the db.
Any other method other than this is also fine. I am stuck with this problem for more than 2 days coudn't find a solution till now. Any help is much Appreciated.
EDIT:
I have tried to update the code but still the same errors.
backend API
router.patch('/up',async (req, res) => {
try{
const id = req.query.userid;
console.log("user id is",id)
console.log("req.body",req.body.body.brandname)
const result= User.findById(id, (error, foundUser) => {
if (foundUser) {
const { products } = foundUser;
const filteredexpenses = products.filter((item) => {
return item._id!= req.body.body._id;
});
while (foundUser.products.length > 0) {
foundUser.products.pop();
}
foundUser.products = filteredexpenses;
foundUser.products.push({
brandname: req.body.body.brandname,
productname: req.body.body.productname,
quantity: req.body.body.quantity,
price: req.body.body.price,
description: req.body.body.description
});
foundUser.save();
}
else
{
console.log('User not found')
}
})
res.status(200).send("update successfull");
}
catch(err){
res.status(403).send('update unsuccessfull')
console.log(err)
}
})
Front end API
const updateproduct = async(req,res) => {
console.warn(values.brandname, values.productname,values.quantity, values.price, values.description)
console.warn("userlogin is:,",userid)
const _id=id;
await axios.patch(`http://localhost:5000/up`,{
headers: {
'Content-type': 'application/json'
},
body:
{'brandname':brandname,'productname':productname,'quantity':quantity,'price':price,'description':description,'_id':_id},
params:{
'userid':userid
}
},
{ withCredentials: true })
.then((res) => {
console.log(res)
navigate('/listproduct')
})
.catch((err) => {
console.log(err)
})
}
Result on console log is
User id is undefined
req.body adidas //brandname
User not found
Try to change your axios request passing all parameters in the body like this:
await axios
.patch(
`http://localhost:5000/up`,
{ brandname, productname, quantity, price, description, _id, userid },
{
headers: {
'Content-type': 'application/json',
},
},
{ withCredentials: true }
)
.then((res) => {
console.log(res);
navigate('/listproduct');
})
.catch((err) => {
console.log(err);
});
And handle the end point like this:
router.patch('/up', async (req, res) => {
try {
const id = req.body.userid;
User.findById(id, async (error, foundUser) => {
if (foundUser) {
const { products } = foundUser;
const { brandname, productname, quantity, price, description, _id } =
req.body;
const filteredexpenses = products.filter((item) => {
return item._id != _id;
});
while (foundUser.products.length > 0) {
foundUser.products.pop();
}
foundUser.products = filteredexpenses;
foundUser.products.push({
brandname,
productname,
quantity,
price,
description,
});
await foundUser.save();
res.status(200).send('update successfull');
} else {
console.log('User not found');
res.status(400).send('User not found');
}
});
} catch (err) {
res.status(403).send('update unsuccessfull');
console.log(err);
}
});

Form Data doesn't show correctly when I send it via Fetch with Node & Muller & Mongoose & GirdFS

I'm trying to upload a new thumbnail with my new quiz, but I'm getting a type of error 500 with the message:
xhr.js:210 POST http://localhost:1234/api/user/61c17715dca0ed0006d92ff9/quizzes/create-quiz 500 (Internal Server Error)
I'm Using MERN stack and GridFS & Muller but I don't know what the error is:
Here is my api base:
const API_BASE_URL = "http://localhost:1234/api/user";
const { user_id, token } = authState.auth;
const client = axios.create({
baseURL: API_BASE_URL,
headers: {
"Content-type": "application/json",
Authorization: "Bearer " + token,
},
});
Here is my API:
export const createQuiz = (data) => async (dispatch) => {
let user = JSON.parse(localStorage.getItem("user"));
const { title, questions, thumbnail, description, category, purchaseCoins, privacy, difficulty } =
data;
const newObj = {
created_by: user.user_id,
title,
description,
category,
questions,
filename: thumbnail,
purchaseCoins,
privacy,
difficulty,
};
console.log("this is it:", newObj);
try {
const response = await api.createQuiz(newObj);
const data = await response.data;
window.location.href = "/dashboard/quizzes";
console.log(data)
dispatch({ type: CONST.ADD_QUIZ_SUCCEEDED, payload: data });
} catch (error) {
console.log(error)
dispatch({ type: CONST.ADD_QUIZ_FAILED, payload: error });
}
};
Here is my React code:
<input
className={styles._form_input}
type="file"
id="l-quiz-name"
name="image"
placeholder="Quiz Name"
onChange={(e) => {
e.preventDefault();
let newData = { ...quiz };
const formData = new FormData();
let currentlyUploaded = e.target.files[0];
formData.append(currentlyUploaded.name, currentlyUploaded);
newData["thumbnail"] = formData;
setQuiz(newData);
}}
/>;
And here is my route at the back:
router.post(
`${prefix}/create-quiz`,
userAuth,
upload.single("thumbnail"),
async (req, res) => {
try {
const user = await User.findOne({ _id: req.params.userId });
console.log(req.file.thumbnail)
const newQuiz = new Quiz({
purchaseCoins: req.body.purchaseCoins,
privacy: req.body.privacy,
created_by: req.params.userId,
category: req.body.category,
title: req.body.title,
description: req.body.description,
difficulty: req.body.difficulty,
questions: req.body.questions,
thumbnail: req.file.filename,
});
console.log(newQuiz);
await newQuiz.save();
user.quizzes.push(newQuiz._id);
await user.save();
return res.status(201).json({
message: "Finally , a quiz created properly !",
success: true,
});
} catch (error) {
return res.status(500).json({
message: "Can't save this quiz try again, check if it already exists",
success: false,
});
}
}
);
And this is the data on how the object is being sent to NodeJS:

Getting Unknown arguments error while creating a charge in stripe in node

Getting Unknown arguments error while creating a charge in stripe with node
nhandledPromiseRejectionWarning: Error: Stripe: Unknown arguments ([object Object]). Did you mean to pass an options object? See https://github.com/stripe/stripe-node/wiki/Passing-Options. (on API request to POST /charges)
The code which i used for the payment
const {v4:uuid4} =require('uuid');
const stripe = require("stripe")(SECRET_KEY);
module.exports = (app) => {
app.post("/payment",(req,res)=>{
const {product, token} = req.body;
console.log("PRICE", product.price);
console.log("PRICE", token.email);
const idempontencyKey = uuid4()
try {
return stripe.customers.create({
email: token.email,
source:token.id
}).then(customer => {
stripe.charges.create(
{
amount: product.price * 100,
currency: 'usd',
customer: customer.id,
receipt_email: token.email,
},
{
idempontencyKey
});
})
.then(result => res.status(200).json(result))
.catch(err => console.log(err))
} catch (err) {
res.send(err);
}
});
}

Resources