refactor: restructure API pagination metadata for better frontend usability
- Create PaginationMetadata model with computed derived fields (total_pages, has_next_page, has_prev_page)
- Update PaginatedListResponse to embed pagination metadata in a separate 'pagination' object
- Add create_pagination_metadata() factory function in utils/pagination.py for consistent computation
- Update all paginated service functions to use new structure:
- history_service.list_history()
- blocklist_service.get_import_logs()
- jail_service.get_jail_banned_ips()
- ban_mappers.map_domain_dashboard_ban_list_to_response()
- Update response model docstrings with new structure examples
- Update Backend-Development.md documentation with new pagination patterns
- Update test fixtures to work with new response structure
Response shape changes from:
{"items": [...], "total": 100, "page": 1, "page_size": 50}
To:
{"items": [...], "pagination": {"page": 1, "page_size": 50, "total": 100, "total_pages": 2, "has_next_page": true, "has_prev_page": false}}
Benefits:
- Frontend receives all pagination state needed for UI controls
- No need for frontend to calculate total_pages or page navigation logic
- Consolidated pagination metadata reduces field sprawl
- OpenAPI schema automatically reflects changes
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -16,9 +16,14 @@ Response Patterns:
|
||||
# Returns:
|
||||
{
|
||||
"items": [...],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"page_size": 20
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total": 100,
|
||||
"total_pages": 5,
|
||||
"has_next_page": true,
|
||||
"has_prev_page": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -116,6 +121,40 @@ class BanGuiBaseModel(BaseModel):
|
||||
model_config = ConfigDict(strict=True)
|
||||
|
||||
|
||||
class PaginationMetadata(BanGuiBaseModel):
|
||||
"""Pagination metadata embedded in paginated list responses.
|
||||
|
||||
Contains page information and computed fields to support frontend pagination controls.
|
||||
|
||||
Fields:
|
||||
page: Current page number (1-based).
|
||||
page_size: Number of items per page.
|
||||
total: Total number of items matching the query (across all pages).
|
||||
total_pages: Computed total number of pages.
|
||||
has_next_page: Whether there is a next page after this one.
|
||||
has_prev_page: Whether there is a previous page before this one.
|
||||
|
||||
Example:
|
||||
```python
|
||||
pagination = PaginationMetadata(
|
||||
page=2,
|
||||
page_size=50,
|
||||
total=150,
|
||||
total_pages=3,
|
||||
has_next_page=True,
|
||||
has_prev_page=True
|
||||
)
|
||||
```
|
||||
"""
|
||||
|
||||
page: int = Field(..., ge=1, description="Current page number (1-based).")
|
||||
page_size: int = Field(..., ge=1, description="Number of items per page.")
|
||||
total: int = Field(..., ge=0, description="Total number of items matching the query.")
|
||||
total_pages: int = Field(..., ge=1, description="Computed total number of pages.")
|
||||
has_next_page: bool = Field(..., description="Whether there is a next page after this one.")
|
||||
has_prev_page: bool = Field(..., description="Whether there is a previous page before this one.")
|
||||
|
||||
|
||||
class PaginatedListResponse(BanGuiBaseModel, Generic[T]):
|
||||
"""Standardized paginated list response.
|
||||
|
||||
@@ -124,9 +163,7 @@ class PaginatedListResponse(BanGuiBaseModel, Generic[T]):
|
||||
|
||||
Fields:
|
||||
items: The data items for the current page.
|
||||
total: Total number of items matching the query (across all pages).
|
||||
page: Current page number (1-based).
|
||||
page_size: Number of items per page.
|
||||
pagination: Pagination metadata with computed derived fields.
|
||||
|
||||
Example:
|
||||
```python
|
||||
@@ -136,17 +173,20 @@ class PaginatedListResponse(BanGuiBaseModel, Generic[T]):
|
||||
# Returns:
|
||||
{
|
||||
"items": [...],
|
||||
"total": 150,
|
||||
"page": 2,
|
||||
"page_size": 50
|
||||
"pagination": {
|
||||
"page": 2,
|
||||
"page_size": 50,
|
||||
"total": 150,
|
||||
"total_pages": 3,
|
||||
"has_next_page": true,
|
||||
"has_prev_page": true
|
||||
}
|
||||
}
|
||||
```
|
||||
"""
|
||||
|
||||
items: list[T] = Field(default_factory=list, description="Data items for the current page.")
|
||||
total: int = Field(..., ge=0, description="Total number of items matching the query.")
|
||||
page: int = Field(..., ge=1, description="Current page number (1-based).")
|
||||
page_size: int = Field(..., ge=1, description="Number of items per page.")
|
||||
pagination: PaginationMetadata = Field(..., description="Pagination metadata with computed derived fields.")
|
||||
|
||||
|
||||
class CollectionResponse(BanGuiBaseModel, Generic[T]):
|
||||
|
||||
Reference in New Issue
Block a user