Skip to content

Instantly share code, notes, and snippets.

@nfarina
Last active January 5, 2023 22:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nfarina/076061118de5c343ccbc08bf8a1c5ce8 to your computer and use it in GitHub Desktop.
Save nfarina/076061118de5c343ccbc08bf8a1c5ce8 to your computer and use it in GitHub Desktop.
Helpful utility functions for iterating objects from the Stripe API using new async iterators
import Stripe from "stripe";
/**
* Utility functions for iterating objects from the Stripe API.
*/
/**
* Iterates over a Stripe API list, automatically handling pagination.
*
* Here's an example that iterates through all balance transactions for a
* given payout:
*
* ```
* const payoutTransactions = iterateList((starting_after, limit) =>
* stripe.balanceTransactions.list({
* payout: "po_123", // Example Payout ID.
* starting_after,
* limit,
* }),
* );
*
* for await (const transaction of payoutTransactions) {
* console.log(transaction.id);
* }
* ```
*/
export async function* iterateList<T extends { id: string }>(
func: (
starting_after: string | undefined,
limit: number,
) => Promise<Stripe.ApiList<T>>,
startingAfter?: string,
): AsyncIterableIterator<T> {
// Retrieve 10 items at a time and increase exponentially.
let limit = 10;
while (true) {
// Fetch the next page of objects.
const result = await func(startingAfter, limit);
// debug(`Retrieved ${result.data.length} results.`);
yield* result.data;
if (!result.has_more) {
// debug("No more results.");
return; // Done!
}
// Start here on the next iteration.
startingAfter = result.data[result.data.length - 1].id;
// Double the limit with a Stripe-imposed maximum amount of 100.
limit = Math.min(limit * 2, 100);
}
}
/**
* Retrieves a complete list of objects from a Stripe API list, automatically
* handling pagination.
*
* Here's an example that retrieves all balance transactions for a given payout:
*
* ```
* const payoutTransactions = await retrieveList((starting_after, limit) =>
* stripe.balanceTransactions.list({
* payout: "po_123", // Example Payout ID.
* starting_after,
* limit,
* }),
* );
*
* for (const transaction of payoutTransactions) {
* console.log(transaction.id);
* }
* ```
*/
export async function retrieveList<T extends { id: string }>(
func: (
starting_after: string | undefined,
limit: number,
) => Promise<Stripe.ApiList<T>>,
): Promise<T[]> {
const objects: T[] = [];
for await (const obj of iterateList(func)) objects.push(obj);
return objects;
}
/**
* Iterates over a Stripe API search, automatically handling pagination.
*
* Here's an example that iterates through all customers with a given name:
*
* ```
* const customers = iterateSearch((page, limit) =>
* stripe.customers.search({
* query: "name:'John'",
* page,
* limit,
* }),
* );
*
* for await (const customer of customers) {
* console.log(customer.id, customer.name);
* }
* ```
*/
export async function* iterateSearch<T extends { id: string }>(
func: (
page: string | undefined,
limit: number,
) => Promise<Stripe.ApiSearchResult<T>>,
page?: string,
): AsyncIterableIterator<T> {
// Retrieve 10 items at a time and increase exponentially.
let limit = 10;
while (true) {
// Fetch the next page of objects.
const result = await func(page, limit);
// debug(`Retrieved ${result.data.length} results.`);
yield* result.data;
if (!result.next_page) {
// debug("No more results.");
return; // Done!
}
// Start here on the next iteration.
page = result.next_page;
// Double the limit with a Stripe-imposed maximum amount of 100.
limit = Math.min(limit * 2, 100);
}
}
/**
* Retrieves a complete list of objects from a Stripe API search, automatically
* handling pagination.
*
* Here's an example that retrieves all customers with a given name:
*
* ```
* const customers = await retrieveSearch((page, limit) =>
* stripe.customers.search({
* query: "name:'John'",
* page,
* limit,
* }),
* );
*
* for (const customer of customers) {
* console.log(customer.id, customer.name);
* }
* ```
*/
export async function retrieveSearch<T extends { id: string }>(
func: (
page: string | undefined,
limit: number,
) => Promise<Stripe.ApiSearchResult<T>>,
): Promise<T[]> {
const objects: T[] = [];
for await (const obj of iterateSearch(func)) objects.push(obj);
return objects;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment