Skip to content

feat: Add API Pagination to Backend List Endpoints#308

Open
sharma-sugurthi wants to merge 3 commits intoAOSSIE-Org:mainfrom
sharma-sugurthi:main
Open

feat: Add API Pagination to Backend List Endpoints#308
sharma-sugurthi wants to merge 3 commits intoAOSSIE-Org:mainfrom
sharma-sugurthi:main

Conversation

@sharma-sugurthi
Copy link

@sharma-sugurthi sharma-sugurthi commented Mar 1, 2026

Summary

This PR implements pagination support for all backend list endpoints to prevent performance degradation as the database grows.

Changes Made

  • New file: Backend/app/utils/pagination.py - Pagination utility module with parameter validation and response formatting
  • Updated: Backend/app/routes/post.py - Added pagination to all 7 GET endpoints:
    • 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 page

Response Format

Returns paginated response with metadata:

{
  "data": [...],
  "skip": 0,
  "limit": 50,
  "count": 50
}

Summary by CodeRabbit

  • New Features
    • Added query-based pagination to all GET endpoints: use skip and limit to navigate large result sets.
    • Default behavior: skip defaults to 0, limit defaults to 50, and limit is capped (max 100).
    • Paginated responses include metadata: returned data, skip, limit, count (returned items), and total_count.

- 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)
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 1, 2026

Warning

Rate limit exceeded

@sharma-sugurthi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 24 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

📥 Commits

Reviewing files that changed from the base of the PR and between d0d260e and d4840c9.

📒 Files selected for processing (1)
  • Backend/app/routes/post.py
📝 Walkthrough

Walkthrough

Adds query-based pagination to seven GET endpoints in Backend/app/routes/post.py and introduces Backend/app/utils/pagination.py with helpers to validate skip/limit and format paginated responses; endpoints now use range-based Supabase queries and return total counts.

Changes

Cohort / File(s) Summary
Pagination Utilities
Backend/app/utils/pagination.py
New module defining DEFAULT_SKIP, DEFAULT_LIMIT, MAX_LIMIT, plus get_pagination_params(skip, limit) and paginate_query(query_result, skip, limit, total_count) for sanitizing params and formatting paginated responses.
Paginated GET Endpoints
Backend/app/routes/post.py
Updated seven GET routes to accept skip: int = Query(...) and limit: int = Query(...), use get_pagination_params and paginate_query, perform .order("id") and .range(start, end) Supabase queries, and include total_count in responses.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰
Hop, skip, and bound I go,
Counting rows in tidy flow,
Limit set and ranges made,
Pages fetch without a braid,
Data served in gentle rows.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Add API Pagination to Backend List Endpoints' directly and clearly describes the main change: implementing pagination for list endpoints.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sharma-sugurthi
Copy link
Author

Please review @Zahnentferner

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 of tuple provides 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.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b38410e and 523934e.

📒 Files selected for processing (3)
  • Backend/app/routes/post.py
  • Backend/app/utils/__init__.py
  • Backend/app/utils/pagination.py

- 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
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
Backend/app/routes/post.py (1)

56-60: Consider removing redundant validation layer.

FastAPI's Query constraints (ge=0, ge=1, le=100) already reject invalid input with a 422 response before the handler executes. The get_pagination_params call then re-validates the same constraints.

If get_pagination_params is 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

📥 Commits

Reviewing files that changed from the base of the PR and between 523934e and d0d260e.

📒 Files selected for processing (2)
  • Backend/app/routes/post.py
  • Backend/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
@sharma-sugurthi
Copy link
Author

also fixed some issues that pointed from the review of bot!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant