Skip to content

Instantly share code, notes, and snippets.

@Lucretiel
Last active November 6, 2021 02:38
Show Gist options
  • Save Lucretiel/c19afc0ea301918afe8f681fdedfdd6c to your computer and use it in GitHub Desktop.
Save Lucretiel/c19afc0ea301918afe8f681fdedfdd6c to your computer and use it in GitHub Desktop.
Utility that fetches from a paginated resource by repeatedly fetching & concatenating pages
// Fetch several rows from 1 or more pages from an API. Concatenate all
// the rows together.
function paginated<Request, Response, Row>(
// A fetch function that retrieves a single page. Intended to wrap a fetch()
// API call (so that you can add your own headers, auth, response parsing,
// etc)
fetcher: (url: Request, cancel?: AbortSignal) => Promise<Response>,
// Given a response, get the URL of the next page, or null if this was the
// last page.
getNextRequest: (response: Response) => Request | null | undefined,
// Given a response, get all the rows in the page. All the rows from all the
// pages will be concatenated for the final response from fetch_paginated.
// If each page is its own row, this can simply be `response => [response]`
getRows: (response: Response, cancel?: AbortSignal) => Promise<Row[]>
): (request: Request, cancel?: AbortSignal) => Promise<Row[]> {
const fetchPage = (
request: Request,
rows: Promise<Row[]>,
cancel?: AbortSignal
): Promise<Row[]> =>
fetcher(request, cancel).then((response) => {
const nextRequest = getNextRequest(response);
const nextRows = getRows(response, cancel);
const allRows = Promise.all([rows, nextRows])
.then(([rows, nextRows]) => rows.concat(nextRows))
return nextRequest == null
? allRows
: fetchPage(nextRequest, allRows, cancel);
});
return (request, cancel) => fetchPage(request, Promise.resolve([]), cancel);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment