0

I apologize if my question seems kind of newbie, I'm very new to async programming and I'm still trying to figure everything out. I'm also trying to figure out how to ask good questions here so i tried to include the right information and a reproducable example. Thank you

I have a simple online store i'm building that only has four products.

When my server side client receives the users cart contents via JSON It receive the product_id, quantity, and price_id as an array of JSON data

I'm trying to configure it to

  1. loop through each array item,

  2. grab the product_id and price_id, send them to the stripe API to recieve the product object and price object respectively,

  3. assign the "unit_amount" value from the price object and the "images" value and "name" value from the products object to their own variable

  4. Put hose variables into an array and push the array to the lineItems array, which is to be used as a variable for the create-session request to Stripe Checkout

in short:

Expected behavior: price_data object produced from each item in the array, array is sent with line_items object to session request to stripe checkout then user is redirected to checkout page with price_data items in checkout.

current behavior: price data retrieved from Stripe api unable to be assigned to variable or passed to price_data. Returning TypeError: Cannot read property 'unit_amount' of undefined.

const stripe = require('stripe')('sk_test_51Hemg7ETi3TpMq6bUmiw1HoxERPmReLOT3YLthf11MEVh4xCmnsmxtFHZRlWpimoSnwHjmUOKNkOFsbr9lEEIybe00SQF71RtF');
//This is a test secret key for a dummy stripe account, don't worry I'm not sharing anything sensitive 
const express = require('express');
const app = express();
app.use(express.static('.'));
const YOUR_DOMAIN = 'http://localhost:4242';



app.post('/create-session', async(req, res) => {
      //Body of the POST request
      const cartContents = [{
          product_id: 'prod_IHb8dX3ESy2kwk',
          quantity: '2',
          price_id: 'price_1Hh1wcETi3TpMq6bSjVCf3EI'
        },
        {
          product_id: 'prod_IFIIyTO0fHCfGx',
          quantity: '2',
          price_id: 'price_1HeniJETi3TpMq6bPDWb3lrp'
        }
      ]

      //Array to push parsed data onto for line_items object in stripe session
      var lineItems = [];

      cartContents.forEach(async(item, index, array) => {
        //Retrieve price object from stripe API:
        const price = await stripe.prices.retrieve(
          item.price_id
        ).then(
          function(message) {
            console.log(message.unit_amount);
            //log the unit_amount value from price object
          },
          function(error) {
            console.log("Reject:", error);
          }
        );
        //retrieve product object from stripe API
        const product = await stripe.products.retrieve(

          item.product_id
        ).catch(err => console.error('error also'));

        console.log(product.name)

        // retrieve "name" and "images" from returned product object and assign to variable
        const productName = product.name;
        const productImage = product.images;
        //retrieve "unit_amount" from returned price object and assign to variable
        const productPrice = price.unit_amount

        //retrieve item quantity from cartContents object and assign to variable
        const productQuantity = item.quantity

        //Add variables to item and push to lineItems array
        lineItems.push({
          price_data: {
            currency: 'usd',
            product_data: {
              name: productName,
              images: [productImage],
            },
            unit_amount: productPrice,
          },
          quantity: productQuantity,
        })
      });
      const session = await stripe.checkout.sessions.create({
        payment_method_types: ['card'],
        line_items: lineItems,
        mode: 'payment',
        success_url: `http://localhost:5001/success.html`,
        cancel_url: `http://localhost:5001/cancel.html`,
      });
      res.json({
        id: session.id
      });

Thank you

  • `.forEach(async` ... always smells like trouble - use a for...of loop in an async function instead – Jaromanda X Oct 28 '20 at 00:55
  • Hi, I apologize but the suggested question doesn't make any sense to me. Its a different structure and the example in the question doesn't match up with my current code at all. Could you please open the question again? –  Oct 28 '20 at 01:16
  • your code has `.forEach(async` ... the code in the question has `.forEach(async` ... that's the issue, it's exactly the same – Jaromanda X Oct 28 '20 at 01:17
  • The files. its attached to is a function, while the one in my code is json data. The contents are also completely different and the differences don't make any sense to me. –  Oct 28 '20 at 01:20
  • you have other issues though ... for example `const price = await stripe.prices.retrieve( item.price_id ).then( function(message) { ... etc})` .... price will be undefined because the .then returns undefined – Jaromanda X Oct 28 '20 at 01:20
  • Why didn't you point that out and show a solution instead of closing the thread? –  Oct 28 '20 at 01:23
  • because the MAIN issue is the `.forEach(async` that won't work - here's code that should work https://pastebin.com/ug5RpTLk - I've reopened – Jaromanda X Oct 28 '20 at 01:26
  • I've added an answer too – Jaromanda X Oct 28 '20 at 01:30

1 Answers1

1

Your main issue is that .forEach(async is very rarely, if at all, going to work like you expect

However, the other issue is

const price = await stripe.prices.retrieve(item.price_id)
.then(function(message) {
    console.log(message.unit_amount);
    //log the unit_amount value from price object
  },
  function(error) {
    console.log("Reject:", error);
  }
);

This will result in price being undefined - since the .then doesn't return anything

It's always (usually) not a good idea to mix .then/.catch with async/await

So - fixing those two issues - your code becomes

const stripe = require('stripe')('sk_test_51Hemg7ETi3TpMq6bUmiw1HoxERPmReLOT3YLthf11MEVh4xCmnsmxtFHZRlWpimoSnwHjmUOKNkOFsbr9lEEIybe00SQF71RtF');
//This is a test secret key for a dummy stripe account, don't worry I'm not sharing anything sensitive
const express = require('express');
const app = express();
app.use(express.static('.'));
const YOUR_DOMAIN = 'http://localhost:4242';

app.post('/create-session', async(req, res) => {
    //Body of the POST request
    const cartContents = [{
            product_id: 'prod_IHb8dX3ESy2kwk',
            quantity: '2',
            price_id: 'price_1Hh1wcETi3TpMq6bSjVCf3EI'
        }, {
            product_id: 'prod_IFIIyTO0fHCfGx',
            quantity: '2',
            price_id: 'price_1HeniJETi3TpMq6bPDWb3lrp'
        }
    ];

    //Array to push parsed data onto for line_items object in stripe session
    const lineItems = [];
    try {
        for (let item of cartContents) {
            //Retrieve price object from stripe API:
            const price = await stripe.prices.retrieve(item.price_id);
            console.log(price.unit_amount);
            //log the unit_amount value from price object
            //retrieve product object from stripe API
            const product = await stripe.products.retrieve(item.product_id);
            console.log(product.name);
            // retrieve "name" and "images" from returned product object and assign to variable
            const productName = product.name;
            const productImage = product.images;
            //retrieve "unit_amount" from returned price object and assign to variable
            const productPrice = price.unit_amount;
            //retrieve item quantity from cartContents object and assign to variable
            const productQuantity = item.quantity;
            //Add variables to item and push to lineItems array
            lineItems.push({
                price_data: {
                    currency: 'usd',
                    product_data: {
                        name: productName,
                        images: [productImage],
                    },
                    unit_amount: productPrice,
                },
                quantity: productQuantity,
            });
        }
        const session = await stripe.checkout.sessions.create({
            payment_method_types: ['card'],
            line_items: lineItems,
            mode: 'payment',
            success_url: `http://localhost:5001/success.html`,
            cancel_url: `http://localhost:5001/cancel.html`,
        });
        res.json({id: session.id});
    } catch(e) {
        // handle error here
    }
});
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87