question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add support for auto pagination when fetching results

See original GitHub issue

Hi, I’m currently working on a project where this would be useful. For each method that fetches paginated results, it’d be nice if there existed a convenience method that fetched all the pages in parallel.

Take getMySavedTracks for example, which has a maxinum number of 50 results per page. We’d have a method called:

getAllMySavedTracks(maxPages, optionsEach, callbackEach, callback)

Which fetches the first page, checks the total items, and creates requests if needed for each page using a limit and offset. The parameters could work as follows:

  • maxPages: The maximum number of pages to get. By default it would request all of them (unless there’s a rate limit for pages Spotify imposes that I don’t know of).
  • optionsEach: The object for options to send in each call to getMySavedTracks. Passing limit and offset would have no effect since that’s automatically determined per each page request in this method.
  • callbackEach: A callback function for each page request i.e. each call to getMySavedTracks. The callback function receives the error and value parameters of course.
  • callback: A callback function that fires after completion of all requests. Just going off of how Promise.all() works, you could pass it the array of values from all the resolved getMySavedTracks promises in the second parameter, and If any of the page requests fail, you only get the value of the promise that was rejected in the first parameter.

Currently, I do this on my own and it gets messy fast. Putting it in the API wrapper could save developers some headaches. If the paging could somehow be generalized, you’d end up with several clean convenience methods. The main usecase for this is for when dealing with a user who has a large music collection (personally I hoard and create too many playlists).

Let me know what you think. I’m totally willing to implement this, as I already have existing code I could refine to work within the wrapper.

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:3
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

6reactions
omarryhancommented, Jun 4, 2020

I made this Typescript auto pagination helper. Unfortunately it doesn’t run in parallel, but I hope some would find it useful:

interface Pagination {
  next?: string;
  items: object[];
}

export const getAllPages = async <Response extends Pagination>(
  request: Promise<Response>,
): Promise<Response> => {
  const paginatedResponse = await request;

  let currentResponse = paginatedResponse;

  while (currentResponse.next) {
    currentResponse = await spotifyApi.getGeneric(
      currentResponse.next,
    ) as Response;
    paginatedResponse.items = paginatedResponse.items.concat(currentResponse.items);
  }

  return paginatedResponse;
};

To call it:

const paginatedResponse = await getAllPages<SpotifyApi.PlaylistTrackResponse>(
  spotifyApi.getPlaylistTracks(playlistId, { limit: 50 }),
);
2reactions
JMPerezcommented, Mar 23, 2015

Hi @mchateloin,

This sounds really interesting. I have thought of that in the past and it all depends on how smart you want the wrapper to be. At the moment it is just a mapping 1:1 with the Web API, which works well for most cases except for the ones you mentioned.

I already had a similar situation when coding the Spotify Deduplicator. In the end I would fetch the first page of items to get the length of the collection, and then would generate promises for the rest of the pages.

The main issue with having methods returning so many items is that they hide the undergoing requests. Due to the rate limiting of the Web API, one can easily exceed it when fetching all user’s saved tracks or all user’s playlists. Actually, that is what happened with certain users with a very large collection of music. So I decided to throttle the promises, delaying them a little bit to make sure I wasn’t making too many requests, following an approach which I moved later to its own package.

In the end I thought that the cases in which one would have to traverse many pages in a collection would be few, and I wanted for the developer to be able to set a certain rate limit, so the wrapper wouldn’t blindly make a ton of requests.

I think a good start is that you create something on top of the wrapper that can generically manage pagination and get X results or all results. And internally it would handle queueing the requests and managing rate limiting.

Read more comments on GitHub >

github_iconTop Results From Across the Web

A guide to pagination, load more buttons, and infinite scroll
Here, we explain a few methods of setting up pagination, load more buttons, and infinite scroll to create more dynamic web pages.
Read more >
Core pagination API - Apollo GraphQL Docs
Call the fetchMore function to fetch the next page of results when needed; Merge individual pages of results into a single list in...
Read more >
How does auto-pagination work for queries? - Retool Forum
I'm trying to get all the results from an Airtable spreadsheet. The Airtable API only returns 100 rows at a time, and supports...
Read more >
The best database pagination technique is … | by Matej Bačo
Thanks to pagination, we can split our large dataset into chunks ( or pages ) that we can gradually fetch and display to...
Read more >
Paginate results in InstantSearch.js - Algolia
Leveraging page and hitsPerPage is best practice for adding pagination functionality. However, there are some cases where you will want to ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found