Skip to content

Commit 1c37916

Browse files
Merge pull request #89 from carvalhocaio/main
feat: add pagination to item endpoint by using fastapi-pagination
2 parents 42e99ca + 2882856 commit 1c37916

File tree

22 files changed

+15889
-468
lines changed

22 files changed

+15889
-468
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ fail_fast: true
22

33
repos:
44
- repo: https://github.com/pre-commit/pre-commit-hooks
5-
rev: v4.5.0
5+
rev: v5.0.0
66
hooks:
77
- id: check-added-large-files
88
args: ["--maxkb=500"]
@@ -19,7 +19,7 @@ repos:
1919

2020
- repo: https://github.com/astral-sh/ruff-pre-commit
2121
# Ruff version.
22-
rev: v0.1.8
22+
rev: v0.12.2
2323
hooks:
2424
# Run the linter.
2525
- id: ruff

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ frontend TypeScript client, `nextjs-frontend`.
77
The backend and the frontend are versioned together, that is, they have the same version number.
88
When you update the backend, you should also update the frontend to the same version.
99

10+
## 0.0.5 <small>July 9, 2025</small> {id="0.0.5"}
11+
12+
- Items Pagination
13+
1014
## 0.0.4 <small>July 9, 2025</small> {id="0.0.4"}
1115

1216
- Fix ESlint missing for pre-commit

fastapi_backend/alembic_migrations/versions/402d067a8b92_added_user_table.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""Added user table
22
33
Revision ID: 402d067a8b92
4-
Revises:
4+
Revises:
55
Create Date: 2024-09-27 14:01:44.155160
66
77
"""
8+
89
from typing import Sequence, Union
910

1011
import fastapi_users_db_sqlalchemy

fastapi_backend/alembic_migrations/versions/b389592974f8_add_item_model.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
Create Date: 2024-12-06 17:52:50.698249
66
77
"""
8+
89
from typing import Sequence, Union
910

1011
from alembic import op

fastapi_backend/app/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from fastapi import FastAPI
2+
from fastapi_pagination import add_pagination
23
from .schemas import UserCreate, UserRead, UserUpdate
34
from .users import auth_backend, fastapi_users, AUTH_URL_PATH
45
from fastapi.middleware.cors import CORSMiddleware
@@ -49,3 +50,4 @@
4950

5051
# Include items routes
5152
app.include_router(items_router, prefix="/items")
53+
add_pagination(app)

fastapi_backend/app/routes/items.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from uuid import UUID
22

3-
from fastapi import APIRouter, Depends, HTTPException
3+
from fastapi import APIRouter, Depends, HTTPException, Query
4+
from fastapi_pagination import Page, Params
5+
from fastapi_pagination.ext.sqlalchemy import apaginate
46
from sqlalchemy.ext.asyncio import AsyncSession
57
from sqlalchemy.future import select
68

@@ -12,14 +14,20 @@
1214
router = APIRouter(tags=["item"])
1315

1416

15-
@router.get("/", response_model=list[ItemRead])
17+
def transform_items(items):
18+
return [ItemRead.model_validate(item) for item in items]
19+
20+
21+
@router.get("/", response_model=Page[ItemRead])
1622
async def read_item(
1723
db: AsyncSession = Depends(get_async_session),
1824
user: User = Depends(current_active_user),
25+
page: int = Query(1, ge=1, description="Page number"),
26+
size: int = Query(10, ge=1, le=100, description="Page size"),
1927
):
20-
result = await db.execute(select(Item).filter(Item.user_id == user.id))
21-
items = result.scalars().all()
22-
return [ItemRead.model_validate(item) for item in items]
28+
params = Params(page=page, size=size)
29+
query = select(Item).filter(Item.user_id == user.id)
30+
return await apaginate(db, query, params, transformer=transform_items)
2331

2432

2533
@router.post("/", response_model=ItemRead)

fastapi_backend/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "app"
3-
version = "0.0.4"
3+
version = "0.0.5"
44
description = ""
55
authors = [{ name = "Anderson Resende", email = "[email protected]" }]
66
requires-python = ">=3.12,<3.13"
@@ -11,6 +11,7 @@ dependencies = [
1111
"fastapi-users[sqlalchemy]>=13.0.0,<14",
1212
"pydantic-settings>=2.5.2,<3",
1313
"fastapi-mail>=1.4.1,<2",
14+
"fastapi-pagination==0.13.3"
1415
]
1516

1617
[dependency-groups]

fastapi_backend/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,3 +516,4 @@ websockets==14.1 \
516516
--hash=sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707 \
517517
--hash=sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05 \
518518
--hash=sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed
519+
fastapi-pagination==0.13.3

fastapi_backend/tests/routes/test_items.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,31 @@ async def test_read_items(self, test_client, db_session, authenticated_user):
4848
for item_data in items_data:
4949
await db_session.execute(insert(Item).values(**item_data))
5050

51-
# Read items
51+
await db_session.commit() # Add commit to ensure items are saved
52+
53+
# Read items - test pagination response
5254
read_response = await test_client.get(
5355
"/items/", headers=authenticated_user["headers"]
5456
)
5557
assert read_response.status_code == status.HTTP_200_OK
56-
items = read_response.json()
58+
response_data = read_response.json()
59+
60+
# Check pagination structure
61+
assert "items" in response_data
62+
assert "total" in response_data
63+
assert "page" in response_data
64+
assert "size" in response_data
65+
66+
items = response_data["items"]
67+
68+
# Filter items created in this test (to avoid interference from other tests)
69+
test_items = [
70+
item for item in items if item["name"] in ["First Item", "Second Item"]
71+
]
5772

58-
assert len(items) == 2
59-
assert any(item["name"] == "First Item" for item in items)
60-
assert any(item["name"] == "Second Item" for item in items)
73+
assert len(test_items) == 2
74+
assert any(item["name"] == "First Item" for item in test_items)
75+
assert any(item["name"] == "Second Item" for item in test_items)
6176

6277
@pytest.mark.asyncio(loop_scope="function")
6378
async def test_delete_item(self, test_client, db_session, authenticated_user):

0 commit comments

Comments
 (0)