Last active
January 5, 2023 22:56
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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