Skip to main content

Build a TypeScript SDK with Pagination

This tutorial includes the following SDK languages and versions:

TypeScriptJavaPythonC#GoPHP

Pagination is crucial for managing large datasets, as it allows for efficient data retrieval by splitting the data into smaller, more manageable chunks. The offset-limit pagination approach uses two parameters:

  • Limit: Specifies the number of items to return per page.
  • Offset: Indicates where the data should start, skipping a defined number of records.

Implementing offset-limit pagination involves complex query configurations. Instead of configuring complex queries, liblab’s solution lets you handle pagination effortlessly. You can either:

  • Automatically iterate through all data, receiving results in manageable pages.
  • Use the next() function to navigate page by page, fetching the next data set only when needed.

This tutorial covers two methods for adding pagination to a TypeScript SDK using liblab’s solution:

  1. Configuring the OpenAPI spec with the x-liblab-pagination annotation.
  2. Customizing the SDK through the liblab.config.json file.

Prerequisites

Package Manager

liblab CLI supports multiple package managers. Check the Getting started overview for more details.

Steps

  1. Set up the project
  2. Configure the pagination feature
    • Using the OpenAPI spec
    • Using the liblab.config.json file
  3. Generate the SDK
  4. Test the SDK

1. Set up the Project

First, log in to liblab using the following command:

liblab login

Now, you are ready to create the project. Create a new directory for your project called typescript-pagination and initialize the project by running the following commands:

mkdir -p typescript-pagination
cd typescript-pagination
liblab init

A new liblab.config.json file will be created, containing all basic configurations for generating SDKs for four different programming languages:

  • C#
  • GO
  • Python
  • TypeScript

However, for this tutorial, we will only use TypeScript. Edit the liblab.config.json file to only include TypeScript by modifying the languages array:

"languages": [
"typescript"
],

2. Configure the pagination feature

liblab offers two ways to add pagination to your SDK:

  • Using the OpenAPI spec.
  • Directly via the liblab.config.json file.

Both methods achieve the same goal, so choose the one that best fits your workflow.

Pagination Documentation

For more information on pagination settings, access the pagination documentation.

Below, you can choose one of the guides to follow with this tutorial to add the pagination feature to one endpoint of the Pokemon API.

To configure pagination using the OpenAPI spec:

  1. Download the modified Pokémon API spec, which contains only the Get All Pokémon endpoint, and save it as pokemon.yaml in your project directory. Your directory structure should look like this:
typescript-pagination/
├── liblab.config.json
└── pokemon.yaml
  1. Update your liblab.config.json file to reference the Pokemon API you added to the directory:
"specFilePath": "./pokemon.yaml"

After completing these steps, you can configure pagination in the OpenAPI spec. In this example, you’ll add pagination to the GET /api/v2/pokemon/ endpoint, which lists all Pokémons available.

The code block below highlights the necessary changes to the OpenAPI spec.

pokemon.yaml
paths:
/api/v2/pokemon/:
get:
operationId: pokemon_list
summary: List pokemon
x-liblab-pagination:
paginationType: offsetLimit
inputFields:
- name: offset
in: query
type: offset
- name: limit
in: query
type: limit
resultsArray:
results: "$.results"
tags:
- pokemon
parameters:
- name: limit
in: query
description: The maximum number of items to return in the response.
required: true
schema:
type: integer
format: int32
- name: offset
in: query
description: The number of items to skip before starting to collect the result set.
required: true
schema:
type: integer
format: int32

To add the pagination feature, you have to add the x-liblab-pagination annotation to specify pagination settings. In the above code, the pagination type is set to offsetLimit, which will be controlled by the offset and limit query parameters.

The inputFields section defines the pagination inputs:

  • name: Specifies the parameter's name (offset or limit). It's important to note that the names used must match those used by the API server.
  • type: Indicates whether it’s an offset or limit.
  • in: Describes how the parameter is passed to the endpoint, in this case, as a query parameter. Currently, only the query option is available in liblab.

The resultsArray object specifies the data location in the API response. The resultsArray.results property should point to the array containing the results. If this is not correctly configured, errors may occur when using the SDK, as the SDK expects the response to return an array.

In this example, the API response uses the following schema:

{
"results": [],
"count": 123,
"next": "http://api.example.org/accounts/?offset=400&limit=100",
"previous": "http://api.example.org/accounts/?offset=200&limit=100"
}

Therefore, the resultsArray.results property should be set to $.results to ensure the SDK references the correct data for pagination.

The parameters section, highlighted above, defines how the pagination parameters are handled:

  • The name in the parameters must match the names in the inputFields.
  • Both parameters (limit and offset) must be marked as required: true.
  • Specify the schema, defining the parameter type: integer and format: int32.
Name

It's important to note that the names of the pagination parameters, such as offset and limit, must match those used by the API running on your server. Otherwise the SDK won't function properly.

After setting this up, you can proceed to generate the SDK.

3. Generate the SDK

Once you've configured pagination, generate the SDK by running:

liblab build

The liblab CLI will validate and notify you about any issues with the liblab.config.json or the pokemon.json files.

CLI Warning

If you receive the message:

It is important to fix your spec before continuing with a build. Not fixing the spec may yield a subpar SDK and documentation. Would you like to attempt to build the SDK anyway? (Y/n)

Type Y to continue.

liblab CLI checks if errors exist in the OpenAPI spec and warns you because the existing errors may affect the SDK behavior. If you facing this warning while following this tutorial, you can type Y since you'll be using a tested spec.

After a successful build, you should see the following message on your terminal:

Your SDKs are being generated. Visit the liblab portal (<link to the liblab page>) to view more details on your build(s).
✓ TypeScript built
Successfully generated SDKs downloaded. You can find them inside the <your-repository> folder
✓ Generate package-lock.json for TypeScript
Successfully generated SDK's for TypeScript ♡

The SDK will be generated and saved in the /output/typescript directory, which should have the following structure:

/output/typescript
├── documentation/
├── examples/
├── LICENSE
├── node_modules/
├── package.json
├── package-lock.json
├── README.md
├── src/
└── tsconfig.json

The documentation available lists and describes the SDK models and services. Only the pokemonList method will be available for the modified Pokemon API. If you access the service documentation, you will find the details on how to use it:

## pokemonList

- HTTP Method: `GET`
- Endpoint: `/api/v2/pokemon/`

**Parameters**

| Name | Type | Required | Description |
| :----- | :----- | :------- | :----------------------------------- |
| limit | number || How many items to return at one time |
| offset | number || Starting point of data |

4. Test the SDK

To test the SDK, you can use the automatically generated sample code located at the example directory:

  1. Navigate to the /output/typescript/examples/ directory:
cd output/typescript/examples/
  1. Run the following command to set up the TypeScript SDK:
npm run setup
Publish your SDK

The TypeScript SDK is not published to npm. You will be using the local files to run it.

Access the liblab documentation to learn how to publish your SDK.

Once setup is complete, you're ready to test the SDK pagination feature. The following examples show how to test both manual and iterable pagination. Both manual and iterable pagination offer flexibility:

  • Manual pagination gives you control over when to fetch the next page. This is useful for scenarios where you don’t need all data upfront and prefer fetching data on demand.
  • Iterable pagination automatically handles loading all pages as you iterate through them. This is ideal when you need to process all available data sequentially.

Now, you can test both approaches by using using the index.ts file located at output/typescript/examples/src/index.ts and the code examples below.

With manual pagination, you can use the next() function to fetch subsequent data pages based on the defined limit and offset values. Replace the content in output/typescript/examples/src/index.ts with the code below to test a simple implementation of manual pagination for the pokemonList method.

index.ts
import { TypeScriptSdk } from 'typescript-sdk';

(async () => {
const Sdk = new TypeScriptSdk({
token: 'YOUR_TOKEN',
});

const pages = await Sdk.pokemon.pokemonList({
limit: 8,
offset: 0,
});

const firstPage = await pages.next();
console.log(firstPage.value.data);

const secondPage = await pages.next();
console.log(secondPage.value.data);
})();

In the above code:

  1. The TypeScriptSdk is imported from the SDK package typescript-sdk, and a new instance is created.
  2. The pokemonList function from the SDK retrieves a list of Pokémon. The pages variable is an iterable object. Each page will include up to 8 Pokémon, as defined by the limit value. The offset specifies where the first page starts in the list, with offset: 0 meaning the data begins at the first Pokémon. By iterating through pages, you can access each page of data in sequence, with each page containing the number of entries defined by limit.
  3. When the next() method is called for the first time, it retrieves the first page of results.
  4. After, the next() method is called again to fetch the second page of results.

Run the following commant at the output/typescript/examples/ directory to test the code above:

npm run start

The following tabs display the Pokémon data retrieved on each page. Each page contains 8 Pokémon, and the first page starts with the first Pokémon.

[
{ name: 'bulbasaur', url: 'https://pokeapi.co/api/v2/pokemon/1/' },
{ name: 'ivysaur', url: 'https://pokeapi.co/api/v2/pokemon/2/' },
{ name: 'venusaur', url: 'https://pokeapi.co/api/v2/pokemon/3/' },
{ name: 'charmander', url: 'https://pokeapi.co/api/v2/pokemon/4/' },
{ name: 'charmeleon', url: 'https://pokeapi.co/api/v2/pokemon/5/' },
{ name: 'charizard', url: 'https://pokeapi.co/api/v2/pokemon/6/' },
{ name: 'squirtle', url: 'https://pokeapi.co/api/v2/pokemon/7/' },
{ name: 'wartortle', url: 'https://pokeapi.co/api/v2/pokemon/8/' }
]

Applying manual pagination using the next() function allows you to retrieve one page at a time, allowing precise control over data loading.

Conclusion

You can easily manage large datasets using manual or iterable pagination methods by configuring pagination through either the OpenAPI spec or the liblab.config.json file. Whether you need precise control over data fetching or seamless iteration through all results, liblab’s SDK simplifies the process, improving developer experience.