JAVASCRIPT
Iterating Through Cursor-Based Paginated API Results
Efficiently fetch all data from APIs employing cursor-based pagination, ensuring you retrieve every record across multiple pages with async/await.
async function fetchAllPaginatedData(initialUrl, params = {}) {
let allData = [];
let nextUrl = initialUrl;
let hasMore = true;
while (hasMore) {
try {
const url = new URL(nextUrl);
// Add initial parameters only for the first request if not already in nextUrl
if (nextUrl === initialUrl) {
Object.keys(params).forEach(key => url.searchParams.set(key, params[key]));
}
console.log(`Fetching from: ${url.toString()}`);
const response = await fetch(url.toString(), {
headers: {
'Accept': 'application/json',
// 'Authorization': 'Bearer YOUR_TOKEN' // Add if API requires authentication
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
// Assuming data is in 'data' array and pagination info in 'meta' or top-level
// Adapt this part based on your API's actual response structure
if (result.data && Array.isArray(result.data)) {
allData = allData.concat(result.data);
}
// Example: Cursor-based pagination common patterns:
// - 'next_cursor' in meta or top-level
// - 'links.next' providing a full URL
// - 'pagination.next_page_url'
const nextCursor = result.meta?.next_cursor || result.next_cursor;
const nextPageUrl = result.links?.next || result.pagination?.next_page_url;
if (nextCursor) {
// Append cursor to original URL. Might need to handle existing params.
// For simplicity, assuming initialUrl doesn't have a 'cursor' param initially.
const newUrl = new URL(initialUrl);
Object.keys(params).forEach(key => newUrl.searchParams.set(key, params[key]));
newUrl.searchParams.set('cursor', nextCursor);
nextUrl = newUrl.toString();
hasMore = true;
} else if (nextPageUrl) {
// If API provides full next page URL directly
nextUrl = nextPageUrl;
hasMore = true;
} else {
hasMore = false;
}
} catch (error) {
console.error('Error fetching paginated data:', error);
hasMore = false; // Stop iteration on error
}
}
return allData;
}
// Example Usage:
// const baseUrl = 'https://api.example.com/v1/items';
// fetchAllPaginatedData(baseUrl, { limit: 100 })
// .then(items => {
// console.log(`Fetched ${items.length} items.`);
// // console.log(items);
// })
// .catch(err => console.error('Failed to fetch all items:', err));
How it works: This JavaScript snippet demonstrates how to consume a cursor-based paginated API, fetching all available data across multiple pages. Unlike offset-based pagination, cursor-based pagination uses an opaque string (cursor) to mark the last item fetched, making it more robust against data insertions/deletions during iteration. The `fetchAllPaginatedData` function continuously makes `fetch` requests, updating the URL with the `next_cursor` or `next_page_url` provided by the API response, until no further pages are indicated, accumulating all results into a single array.