feat: Add API Pagination to Backend List Endpoints#308
feat: Add API Pagination to Backend List Endpoints#308sharma-sugurthi wants to merge 3 commits intoAOSSIE-Org:mainfrom
Conversation
- Create pagination utility module (utils/pagination.py) - Add pagination support to all 7 list endpoints: - GET /users/ - GET /audience-insights/ - GET /sponsorships/ - GET /posts/ - GET /sponsorship-applications/ - GET /sponsorship-payments/ - GET /collaborations/ - Support skip/limit query parameters with validation - Return paginated response with metadata (data, skip, limit, count)
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds query-based pagination to seven GET endpoints in Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API as FastAPI (post routes)
participant Pager as Pagination Utils
participant DB as Supabase
Client->>API: GET /posts?skip=50&limit=25
API->>Pager: get_pagination_params(skip, limit)
Pager-->>API: (start, end, sanitized_skip, sanitized_limit)
API->>DB: query .order("id").range(start, end)
DB-->>API: paged rows
API->>DB: query count
DB-->>API: total_count
API->>Pager: paginate_query(query_result, skip, limit, total_count)
Pager-->>API: {data, skip, limit, count, total_count}
API-->>Client: 200 OK with paginated payload
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Please review @Zahnentferner |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
Backend/app/utils/pagination.py (1)
9-17: Consider more specific type hint for return value.Using
Tuple[int, int]instead oftupleprovides better type safety and IDE support.♻️ Proposed fix
-from typing import Dict, Any +from typing import Dict, Any, Tuple DEFAULT_SKIP = 0 DEFAULT_LIMIT = 50 MAX_LIMIT = 100 -def get_pagination_params(skip: int = DEFAULT_SKIP, limit: int = DEFAULT_LIMIT) -> tuple: +def get_pagination_params(skip: int = DEFAULT_SKIP, limit: int = DEFAULT_LIMIT) -> Tuple[int, int]: """Validate and return pagination parameters."""🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Backend/app/utils/pagination.py` around lines 9 - 17, The function get_pagination_params currently annotates its return type as generic "tuple"; change it to a concrete Tuple[int, int] for better type safety by updating the signature to use Tuple[int, int] and add the necessary import (from typing import Tuple) at the top of the module; keep the function logic unchanged and ensure any callers expecting a tuple continue to work since Tuple[int, int] is compatible.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Backend/app/routes/post.py`:
- Around line 55-65: The get_users endpoint (and the six other paginated
endpoints in this file) uses supabase.table(...).select(...).range(...) without
an explicit ORDER BY, causing non-deterministic pagination; update each
paginated handler (e.g., get_users) to apply a deterministic order before
calling .range() by adding an explicit order clause on the intended sort column
plus the unique primary key as a tiebreaker (e.g., order("created_at", {
ascending: false }) then order("id", { ascending: true })) so ties are resolved
consistently, and keep using get_pagination_params and paginate_query unchanged;
apply the same pattern to all seven endpoints referenced in the review.
In `@Backend/app/utils/pagination.py`:
- Around line 20-32: The paginate_query function currently returns "count" as
the page length, not the total records; update paginate_query(query_result,
skip: int, limit: int) to include a "total_count" field that represents the full
dataset size by first checking for a total on the result (e.g., use
query_result.count or query_result.total if present) and, if absent,
perform/accept a separate exact-count query result and merge its count; preserve
existing "count" as page length but add "total_count" to the returned dict and
handle missing/None safely (default to len(data)) so clients can compute total
pages and detect more pages.
---
Nitpick comments:
In `@Backend/app/utils/pagination.py`:
- Around line 9-17: The function get_pagination_params currently annotates its
return type as generic "tuple"; change it to a concrete Tuple[int, int] for
better type safety by updating the signature to use Tuple[int, int] and add the
necessary import (from typing import Tuple) at the top of the module; keep the
function logic unchanged and ensure any callers expecting a tuple continue to
work since Tuple[int, int] is compatible.
- Add .order('id') to all paginated queries for deterministic ordering
- Add count query to get total_count for pagination UX
- Update paginate_query to include total_count in response
Addresses CodeRabbit review feedback
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
Backend/app/routes/post.py (1)
56-60: Consider removing redundant validation layer.FastAPI's
Queryconstraints (ge=0,ge=1,le=100) already reject invalid input with a 422 response before the handler executes. Theget_pagination_paramscall then re-validates the same constraints.If
get_pagination_paramsis only used by FastAPI endpoints, consider simplifying it to just return the tuple without re-validation. If it needs to support non-FastAPI callers, the current design is fine.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Backend/app/routes/post.py` around lines 56 - 60, The handler get_users currently re-validates pagination that FastAPI already enforces via Query; remove the redundant validation by changing the call to get_pagination_params(skip, limit) so that get_pagination_params no longer re-checks Query constraints and simply returns (skip, limit), or if you need get_pagination_params to remain reusable outside FastAPI keep its validation but call it only from non-FastAPI code—i.e., simplify get_pagination_params to a passthrough (return skip, limit) when used by get_users, and update the function signature/implementation accordingly to avoid duplicate checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Backend/app/routes/post.py`:
- Around line 64-67: The count queries currently fetch full rows (e.g., in the
block that calls supabase.table("users").select("*", count="exact").execute())
which defeats pagination; update each count query to request only the count by
adding .limit(0) before .execute() so no rows are transferred. Apply this change
in all endpoints that compute total_count (functions/getters named
get_audience_insights, get_sponsorships, get_posts,
get_sponsorship_applications, get_sponsorship_payments, get_collaborations and
the users listing that calls paginate_query) and keep using count_result.count
(with the existing fallback to len(count_result.data)) to derive total_count.
Ensure the modified calls still pass the result into paginate_query(result,
skip, limit, total_count).
---
Nitpick comments:
In `@Backend/app/routes/post.py`:
- Around line 56-60: The handler get_users currently re-validates pagination
that FastAPI already enforces via Query; remove the redundant validation by
changing the call to get_pagination_params(skip, limit) so that
get_pagination_params no longer re-checks Query constraints and simply returns
(skip, limit), or if you need get_pagination_params to remain reusable outside
FastAPI keep its validation but call it only from non-FastAPI code—i.e.,
simplify get_pagination_params to a passthrough (return skip, limit) when used
by get_users, and update the function signature/implementation accordingly to
avoid duplicate checks.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Backend/app/routes/post.pyBackend/app/utils/pagination.py
🚧 Files skipped from review as they are similar to previous changes (1)
- Backend/app/utils/pagination.py
- Add .limit(0) to all count queries to prevent fetching data - Returns only count metadata without transferring rows - Addresses CodeRabbit performance feedback
|
also fixed some issues that pointed from the review of bot!!! |
Summary
This PR implements pagination support for all backend list endpoints to prevent performance degradation as the database grows.
Changes Made
GET /users/GET /audience-insights/GET /sponsorships/GET /posts/GET /sponsorship-applications/GET /sponsorship-payments/GET /collaborations/Implementation Details
Query Parameters
All list endpoints now accept:
skip(int, default=0, min=0): Number of records to skip (offset)limit(int, default=50, min=1, max=100): Maximum records to return per pageResponse Format
Returns paginated response with metadata:
{ "data": [...], "skip": 0, "limit": 50, "count": 50 }Summary by CodeRabbit