Pagination#
Fitrequest provides an easy way to handle paginated responses using the @paginated decorator. This decorator accepts an optional argument page_cls, which specifies how pages should be processed.
The default page handler is PageDict, which expects API responses in this format:
{
"results": ["a", "b", "c"],
"next": "https://my.next.page.url"
}
Basic Usage#
Here’s a simple example of how to use pagination with Fitrequest:
from fitrequest.decorators import fit, paginated
from fitrequest.client import FitRequest
class TestClient(FitRequest):
client_name = 'test_client'
base_url = 'https://test.skillcorner.fr'
@paginated
@fit(endpoint='/items/')
def get_items(self, **kwargs) -> list[dict]: ...
@paginated
@fit(endpoint='/items/')
async def async_get_items(self, **kwargs) -> list[dict]: ...
Customizing Field Names#
If your API uses different field names for results and next page URLs, you can create a custom page handler:
from fitrequest.decorators import fit, paginated, PageDict
from fitrequest.client import FitRequest
@dataclass
class CustomPageDict(PageDict):
results_kw: str = 'data' # Field name for results
next_kw: str = 'next_page' # Field name for next page URL
class TestClient(FitRequest):
client_name = 'test_client'
base_url = 'https://test.skillcorner.fr'
@paginated(page_cls=CustomPageDict)
@fit(endpoint='/items/')
def get_items(self, **kwargs) -> list[dict]: ...
@paginated(page_cls=CustomPageDict)
@fit(endpoint='/items/')
async def async_get_items(self, **kwargs) -> list[dict]: ...
Advanced Customization#
For more complex cases, you can create a custom page handler by inheriting from AbstractPage. Your class must implement:
How to extract results and next page URL
How to save results (for Fitrequest’s
save_*methods)
Example: Handling a non-standard response format
from fitrequest.decorators import fit, paginated, AbstractPage
from fitrequest.client import FitRequest
class CustomPageString(AbstractPage):
def __init__(self, data: str) -> None:
self._results, self._next_url = data.split(sep='|', maxsplit=1)
@property
def results(self) -> Iterable:
return map(int, self._results.split(sep=','))
@property
def next_url(self) -> str | None:
return self._next_url if self._next_url != '' else None
@staticmethod
def save_results(filepath: Path, results: list) -> None:
filepath.write_text('\n'.join(str(num) for num in results))
@staticmethod
async def async_save_results(filepath: Path, results: list) -> None:
async with aiofiles.open(filepath, mode='x') as data_file:
await data_file.write('\n'.join(str(num) for num in results))
class TestClient(FitRequest):
client_name = 'test_client'
base_url = 'https://test.skillcorner.fr'
@paginated(page_cls=CustomPageString)
@fit(endpoint='/items/')
def get_items(self, **kwargs) -> list[int]: ...
@paginated(page_cls=CustomPageString)
@fit(endpoint='/items/')
async def async_get_items(self, **kwargs) -> list[int]: ...
Flexibility#
As shown in these examples, Fitrequest’s pagination system is highly flexible. You can easily create custom page handlers to work with any API response format.