Implementing Pagination and Filtering
When your bookmark collection grows to hundreds of entries, fetching the entire list in a single request becomes inefficient. etchblok-test-api provides a paginated and filterable interface through the BookmarkRepository to handle large datasets by requesting specific slices of data.
Fetching Paginated Data via the API
To retrieve a specific subset of bookmarks, you use query parameters on the /bookmarks/ endpoint. The API extracts these parameters and passes them through the BookmarkService to the underlying repository.
In app/routes/bookmarks.py, the route handler demonstrates how to process these requests:
@bookmarks_bp.route("/", methods=["GET"])
def list_bookmarks():
"""Return a paginated list of bookmarks.
Query Parameters:
page (int): Page number, starting from 1.
per_page (int): Items per page (max 100).
status (str): Filter by status (active, archived, trashed).
"""
page = request.args.get("page", 1, type=int)
per_page = request.args.get("per_page", 25, type=int)
status = request.args.get("status", None)
# The service orchestrates the repository call
bookmarks, total = _service.list_bookmarks(page=page, per_page=per_page, status=status)
return jsonify({
"bookmarks": [b.to_dict() for b in bookmarks],
"total": total
})
The response includes both the list of bookmarks for the current page and a total count of all matching items, allowing the frontend to calculate the total number of pages available.
Repository Implementation
The core logic for slicing and filtering data resides in the list_bookmarks method of the BookmarkRepository class in app/db/repository.py.
def list_bookmarks(
self,
page: int = 1,
per_page: int = 25,
status: Optional[str] = None,
) -> Tuple[List[Bookmark], int]:
items = list(self._bookmarks.values())
# 1. Filtering
if status:
try:
target = BookmarkStatus(status)
items = [b for b in items if b.status == target]
except ValueError:
# If status is invalid, the filter is ignored
pass
# 2. Sorting
items.sort(key=lambda b: b.created_at, reverse=True)
# 3. Pagination
total = len(items)
start = (page - 1) * per_page
return items[start : start + per_page], total
Status Filtering
The repository filters items based on the BookmarkStatus enum defined in app/models/bookmark.py. Valid status strings are:
activearchivedtrashed
If you provide a status string that does not match one of these values, the BookmarkRepository catches the ValueError and proceeds without applying any filter, returning bookmarks of all statuses.
Sorting Behavior
The results are always sorted by created_at in descending order (reverse=True). This ensures that the most recently created bookmarks appear on the first page of results.
Pagination Logic
etchblok-test-api uses 1-based indexing for the page parameter. The internal calculation (page - 1) * per_page converts this to the 0-based index required for Python list slicing.
- Page 1: Starts at index
0. - Page 2: Starts at index
per_page. - Out of Bounds: If you request a
pagethat results in astartindex beyond the length of the list, the sliceitems[start : start + per_page]naturally returns an empty list[]rather than raising an error.
Bulk Operations
While the API defaults to 25 items per page, internal services in etchblok-test-api sometimes use the pagination parameters to perform bulk operations. For example, the SearchIndex service (found in app/services/search_service.py) may call list_bookmarks with a very high per_page value (e.g., 10000) to retrieve large chunks of data for index rebuilding.