Mastering Pagination with fetchPaginatedData: A TypeScript Guide
Learn how to build a versatile pagination function to enhance your API wrapper
Why should you learn about that?
When working with APIs, handling paginated data is a common challenge developers face. To manage large datasets and limit the strain on servers, APIs often return paginated data. In this article, we will explore the fetchPaginatedData
function, a powerful and versatile pagination function built using TypeScript, and discuss how it can simplify your API wrapper.
What is the goal of the function?
Providing a seamless experience for users while gracefully handling paginated data is essential. The fetchPaginatedData
function aims to address this challenge and deliver an effective solution.
Building the fetchPaginatedData Function
fetchPaginatedData
is a generic TypeScript function designed to handle pagination effortlessly. Before diving into the function itself, let's define the PaginatedResult
and NextFunction
types, which will be used to provide better type safety and readability:
type PaginatedResult<T> = {
data: T[];
next: NextFunction<T> | null;
};
type NextFunction<T> = () => Promise<PaginatedResult<T> | null>;
PaginatedResult<T>
represents the result of fetching a single page of data, including the data itself and a next
function to fetch the next page. NextFunction<T>
represents the type of the next
function, which returns a Promise that resolves to a PaginatedResult<T>
or null
if there are no more pages.
Now let’s dive into the structure of the fetchPaginatedData
function:
async function fetchPaginatedData<T>(
endpoint: string,
params: { currentPage: number; pageSize: number; [key: string]: any }
): Promise<PaginatedResult<T>> {
// ...implementation details
}
The function’s structure includes:
- A generic function with a type parameter
T
, allows it to handle different data types. - Input parameters:
endpoint
(API endpoint) andparams
(an object containing pagination-related parameters and any additional parameters required by the API). - A return type: a Promise that resolves to a
PaginatedResult<T>
object containing an array of results (T[]
) and anext
function.
By using the PaginatedResult
and NextFunction
types, we can ensure that our fetchPaginatedData
function is more type-safe, readable, and easier to maintain. This approach makes it clear what each part of the function is responsible for and helps us avoid potential type-related issues.
Implementing the fetchPaginatedData Function
Let’s now examine the implementation details of the fetchPaginatedData
function:
async function fetchPaginatedData<T>(
endpoint: string,
params: { currentPage: number; pageSize: number; [key: string]: any }
): Promise<PaginatedResult<T>> {
const { currentPage, pageSize, ...otherParams } = params;
const queryString = new URLSearchParams({ ...otherParams, currentPage, pageSize }).toString();
const url = `${endpoint}?${queryString}`;
try {
const response = await fetch(url);
const data: T = await response.json();
const totalResults = 'totalResults' in data ? (data as any)['totalResults'] : undefined;
const hasMoreResults = currentPage * pageSize < totalResults;
const next: NextFunction<T> | null = hasMoreResults
? async () => {
return fetchPaginatedData<T>(endpoint, { ...params, currentPage: currentPage + 1 });
}
: null;
return { data, next };
} catch (error) {
throw new Error(`Error fetching paginated data: ${error}`);
}
}
This implementation includes:
- Extracting pagination parameters and constructing the API request URL.
- Fetching data and parsing it as JSON.
- Checking if there are more results available.
- Defining the
next
function based on the availability of more results.
Using the fetchPaginatedData Function
Here’s an example of how to use the fetchPaginatedData
function to handle paginated data from a hypothetical API:
async function getPosts(page: number) {
const results = await fetchPaginatedData<Post>("/api/posts", { currentPage: page, pageSize: 10 });
console.log("Current page results:", results.data);
if (results.next) {
console.log("There are more results available");
const nextResults = results.next();
} else {
console.log("No more results available");
}
}
getPosts(1);
Conclusion
With the fetchPaginatedData
function, you can easily handle paginated API data in your TypeScript projects. It's a powerful, reusable tool that can significantly enhance your API wrapper, making it more efficient and user-friendly. Happy coding!