【问题标题】:Retrieve all products with nested prices from stripe?从条纹中检索所有具有嵌套价格的产品?
【发布时间】:2020-10-16 10:20:57
【问题描述】:

我喜欢条带 API 的简单性,但我不确定是否可以检索嵌套对象。我希望能够检索所有产品和价格以在我的网站上公开显示。

我可以这样列出所有价格和产品:

stripe.Price.list(limit=3)
stripe.Products.list(limit=3)

然后,我必须在前端编写一些逻辑,将价格与产品联系起来,区分每月和每年的价格等。我很想把它嵌套起来。这可能吗?

我也不完全确定公开返回的信息是否安全(API 密钥显然是隐藏的)。我想了解更多关于这方面的信息。

【问题讨论】:

    标签: python stripe-payments


    【解决方案1】:

    然后,我必须在前端编写一些逻辑,将价格与产品联系起来,区分月度和年度价格等。我很想把它嵌套起来。这可能吗?

    方法是首先列出 API 中的产品,然后遍历它们并检索与给定产品关联的所有价格:

    Product 对象不包含其价格列表,因此实际上无法发出两个单独的请求:https://stripe.com/docs/api/products/object

    我也不完全确定公开返回的信息是否安全(API 密钥显然是隐藏的)。我想了解更多关于这方面的信息。

    这是一个很好的问题,因为一般来说,只有使用可发布密钥可检索的对象才能安全地直接从 Stripe API 使用客户端。在这些情况下,API 参考将对象上的属性标记为“可使用可发布密钥检索”,例如:

    但是,只要您的服务器端端点不直接返回使用您的密钥检索到的产品/价格对象,而是返回仅包含所需属性的过滤版本,您应该没问题!

    【讨论】:

      【解决方案2】:

      只要对象中存在id,就可以调用expand 参数来返回该项目。

      这可以在用于扩展响应的 Stripe 文档中进一步探索:https://stripe.com/docs/expand

      nodejs 中的解决方案如下:

      const productPriceData = await stripe.prices.list({
        expand: ['data.product'], // ? Give me the product data too!
      })
      

      我实际上遇到了同样的问题,并在这里记录了我是如何找到这个解决方案的:https://blog.focusotter.com/fetch-both-price-and-product-data-from-stripe-in-a-single-api-call

      【讨论】:

      • expand 选项非常有用,但 OP 要求与您的查询相反 - 产品与价格嵌套,而不是价格与产品嵌套。令人沮丧的是,这无法通过 Stripe API 实现!
      【解决方案3】:

      反过来做;获取所有价格,然后获取相应的产品。

      首先创建您的 Stripe 实例,然后从您的函数中请求数据

      // index.ts
      import { getStripeProduct, getStripeProducts } from './products'
      import * as express from 'express'
      import Stripe from 'stripe'
      const router = express.Router()
      const stripe = (apiKey:string) => {
        return new Stripe(apiKey, {
          apiVersion: "2020-08-27",
          typescript: true
        });
      }
      
      // GET a product 
      router.get('/product/:id', async (req: express.Request, res: express.Response) => {
        console.log(`API call to GET /public/product/${req.params.id}`)
        await getStripeProduct(stripe(STRIPE_SECRET_KEY)), req.params.id )
        .then((product) => {
          respond(res, {data: product})
        })
        .catch((error) => {
          respond(res, {code: error.statusCode, message: error.message})
        })
      })
      
      // GET a product list
      router.get('/products', async (req: express.Request, res: express.Response) => {
        console.log('API call to GET /public/products')
        await getStripeProducts(stripe(STRIPE_SECRET_KEY))
        .then((products) => {
          respond(res, {data: products})
        })
        .catch((error) => {
          console.error(error)
          respond(res, {code: error.statusCode, message: error.message})
        })
      })
      
      // products.ts
      import { ProductModel } from '../../models'
      import { Stripe } from 'stripe'
      
      export async function getStripeProduct(stripe: Stripe, id: string) {
        return new Promise((resolve, reject) => {
          stripe.prices.retrieve(id)
          .then(async (price) => {
            const product: ProductModel = {
              id: price.id,
              name: 'Unnamed Product',
              price: price.unit_amount,
              recurring: price.recurring || undefined,
              metadata: price.metadata
            }
              if(typeof(price.product) == 'string') {
              await stripe.products.retrieve(price.product)
              .then((stripeProduct) => {
                product.name = stripeProduct.name
                product.caption = stripeProduct.description || undefined
                product.images = stripeProduct.images || undefined
                product.active = stripeProduct.active
                resolve(product)
              })
            }
            resolve(product)
          })
          .catch((error:any) => {
            reject(error)
          })
        })
      }
      
      export async function getStripeProducts(stripe: Stripe) {
        return new Promise((resolve, reject) => {
          stripe.prices.list()
          .then(async (prices) => {
            const products: ProductModel[] = []
            for(let price of prices.data) {
              const product: ProductModel = {
                id: price.id,
                name: 'Unnamed Product',
                price: price.unit_amount,
                recurring: price.recurring || undefined,
                metadata: price.metadata
              }
              if(typeof price.product == 'string') {
                await stripe.products.retrieve(price.product)
                .then((stripeProduct) => {
                  product.name = stripeProduct.name
                  product.caption = stripeProduct.description || undefined
                  product.images = stripeProduct.images || undefined
                  product.active = stripeProduct.active
                  products.push(product)
                })
              }
            }
            resolve(products)
          })
          .catch((error:any) => {
            reject(error)
          })
        })
      }
      
      // Product Model
      export interface ProductModel {
        id: string;
        name: string;
        caption?: string;
        description?: string;
        active?: boolean;
        images?: string[];
        price?: string | number | null;
        recurring?: {
          interval: string,
          interval_count: number
        },
        metadata?: object
      }
      
      export class ProductModel implements ProductModel {
        constructor(productData?: ProductModel) {
          if (productData) {
            Object.assign(this, productData);
          }
        }
      }
      

      注意:我有一个名为 respond 的实用程序函数,它可以标准化我们的 API 响应。你可以res.send回复

      【讨论】:

        【解决方案4】:

        先阅读 ttmarek 的回答。 但是,请注意,如果您需要所有答案,这些页面似乎并未提供完整示例。来自"List all Prices"

        数组中的每个条目都是一个单独的价格对象。如果没有更多价格 可用,结果数组将为空。

        正如它所说,以及is also stated herein the docs,要获取所有这些,您需要循环直到结果数组为空......

        这里有一些代码可以为您提供所有产品和所有价格...

        import stripe
        stripe.api_key = stripe_test_private_key
        def get_all_stripe_objects(stripe_listable):
            objects = []
            get_more = True
            starting_after = None
            while get_more:
                #stripe.Customer implements ListableAPIResource(APIResource):
                resp = stripe_listable.list(limit=100,starting_after=starting_after)
                objects.extend(resp['data'])
                get_more = resp['has_more']
                if len(resp['data'])>0:
                    starting_after = resp['data'][-1]['id']
            return objects
        all_stripe_products = get_all_stripe_objects(stripe.Product)
        all_stripe_prices = get_all_stripe_objects(stripe.Price)
        

        【讨论】:

          猜你喜欢
          • 2021-07-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-19
          • 1970-01-01
          • 2019-10-29
          • 2023-03-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多