Pagination
LightAPI supports two pagination styles, configured via Meta.pagination. Pagination is applied automatically to GET list responses.
Quick Start
from lightapi import RestEndpoint, Pagination
class PostEndpoint(RestEndpoint):
title: str
body: str
class Meta:
pagination = Pagination(style="page_number", page_size=20)
Pagination constructor
| Parameter | Values | Description |
|---|---|---|
style |
"page_number" |
Offset-based pagination with ?page= param. |
style |
"cursor" |
Cursor-based pagination — efficient for large, append-only datasets. |
page_size |
integer ≥ 1 | Default number of items per page. |
Page-Number Pagination
Response format
Query parameters
| Param | Default | Description |
|---|---|---|
page |
1 |
Page number (1-indexed). |
Example
from lightapi import RestEndpoint, Pagination, Filtering, FieldFilter
class ArticleEndpoint(RestEndpoint):
title: str
published: bool
class Meta:
pagination = Pagination(style="page_number", page_size=10)
filtering = Filtering(backends=[FieldFilter], fields=["published"])
Cursor Pagination
Cursor pagination uses an opaque cursor instead of page numbers. It is more efficient for large datasets because it avoids OFFSET scans.
Response format
When next is null, there are no more pages.
Query parameters
| Param | Description |
|---|---|
cursor |
Opaque cursor from a previous response's next field. Omit for the first page. |
Example
class EventEndpoint(RestEndpoint):
name: str
timestamp: str
class Meta:
pagination = Pagination(style="cursor", page_size=50)
# First page
GET /events
# Next page using the cursor from the previous response
GET /events?cursor=eyJpZCI6IDUwfQ==
Pagination with Filtering
Filtering and pagination compose naturally:
from lightapi import RestEndpoint, Pagination, Filtering, FieldFilter, OrderingFilter
class ProductEndpoint(RestEndpoint):
name: str
price: float
in_stock: bool
class Meta:
pagination = Pagination(style="page_number", page_size=25)
filtering = Filtering(
backends=[FieldFilter, OrderingFilter],
fields=["in_stock"],
ordering=["price", "name"],
)
No Pagination (default)
If Meta.pagination is not set, the GET list endpoint returns all matching rows as a flat list:
This is fine for small datasets. For large tables, always add pagination.
YAML configuration
Configure pagination directly in lightapi.yaml:
# Default pagination applied to all endpoints
defaults:
pagination:
style: page_number
page_size: 20
endpoints:
- route: /posts
fields:
title: { type: str }
meta:
methods: [GET, POST]
# Inherits defaults — no pagination block needed
- route: /events
fields:
name: { type: str }
meta:
methods: [GET, POST]
pagination:
style: cursor # overrides the default for this endpoint
page_size: 50
Behavior notes
- A
pagebeyond the last page returns{"count": N, "pages": M, "results": []}— never an error. - A malformed or expired cursor silently falls back to the first page — never a 500.
- Cursor pagination encodes the last-seen row ID; it does not guarantee stable ordering across concurrent inserts. Pair it with
orderingfromFilteringConfigif stable order matters. - The
countandpageskeys in page-number responses reflect the filtered total whenfilteringis also configured.
Pagination + filtering interaction
from lightapi import RestEndpoint, Pagination, Filtering, FieldFilter, OrderingFilter
class ProductEndpoint(RestEndpoint):
name: str
in_stock: bool
price: float
class Meta:
pagination = Pagination(style="page_number", page_size=10)
filtering = Filtering(
backends=[FieldFilter, OrderingFilter],
fields=["in_stock"],
ordering=["price"],
)