208 lines
6.0 KiB
Python
208 lines
6.0 KiB
Python
"""Base response wrapper models for standardized API envelopes.
|
|
|
|
All API endpoints should wrap their responses using the base classes defined here.
|
|
This ensures a consistent response shape across the entire API, reducing frontend
|
|
branching logic and integration bugs.
|
|
|
|
Response Patterns:
|
|
|
|
1. **Paginated List** — Use `PaginatedListResponse[T]` for endpoints returning paginated items.
|
|
Example: GET /api/jails, GET /api/dashboard/bans
|
|
|
|
```python
|
|
class MyListResponse(PaginatedListResponse[MyItem]):
|
|
pass
|
|
|
|
# Returns:
|
|
{
|
|
"items": [...],
|
|
"total": 100,
|
|
"page": 1,
|
|
"page_size": 20
|
|
}
|
|
```
|
|
|
|
2. **Simple Collection** — Use `CollectionResponse[T]` for non-paginated collections.
|
|
Example: GET /api/bans/active
|
|
|
|
```python
|
|
class MyCollectionResponse(CollectionResponse[MyItem]):
|
|
pass
|
|
|
|
# Returns:
|
|
{
|
|
"items": [...],
|
|
"total": 50
|
|
}
|
|
```
|
|
|
|
3. **Single Item Detail** — Use domain model directly wrapped in a named field.
|
|
Example: GET /api/jails/{name}, GET /api/dashboard/status
|
|
|
|
```python
|
|
class MyDetailResponse(BaseModel):
|
|
jail: Jail # or: status: ServerStatus, settings: ServerSettings
|
|
# Optional extra fields (ignore_list, warnings, etc.)
|
|
|
|
# Returns:
|
|
{
|
|
"jail": {...},
|
|
"ignore_list": [...]
|
|
}
|
|
```
|
|
|
|
4. **Command/Action Result** — Use `CommandResponse` for success/acknowledgement.
|
|
Example: POST /api/jails/{name}/start, POST /api/bans
|
|
|
|
```python
|
|
class MyCommandResponse(CommandResponse):
|
|
jail: str # Optional: target identifier
|
|
|
|
# Returns:
|
|
{
|
|
"message": "Jail 'sshd' started.",
|
|
"success": true,
|
|
"jail": "sshd"
|
|
}
|
|
```
|
|
|
|
5. **Aggregated Data** — Use domain-specific aggregation models with metadata.
|
|
Example: GET /api/dashboard/bans/by-jail
|
|
|
|
```python
|
|
class MyAggregationResponse(BaseModel):
|
|
jails: list[JailBanCount] # or: countries, buckets, etc.
|
|
total: int
|
|
# Optional: filters, time_range metadata
|
|
|
|
# Returns:
|
|
{
|
|
"jails": [...],
|
|
"total": 1234
|
|
}
|
|
```
|
|
|
|
Note on field naming:
|
|
- Paginated/collection responses always use "items" for the data array.
|
|
- Detail responses use domain-specific field names (jail, status, settings).
|
|
- Aggregation responses use domain-specific field names (jails, countries, buckets).
|
|
- All responses with multiple items include a "total" field.
|
|
"""
|
|
|
|
from typing import Generic, TypeVar
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
class BanGuiBaseModel(BaseModel):
|
|
"""Project-wide Pydantic base model.
|
|
|
|
Enforces the canonical **snake_case** API field naming policy:
|
|
all JSON wire-format field names use ``snake_case`` on both the backend
|
|
(Python) and the frontend (TypeScript interfaces). No ``alias_generator``
|
|
is applied — field names are serialized exactly as written.
|
|
|
|
Rules:
|
|
- Every model in ``app/models/`` must inherit from this class.
|
|
- Field names must be ``snake_case`` in Python *and* in the JSON payload.
|
|
- The corresponding TypeScript interface fields must also be ``snake_case``.
|
|
- Never add a ``camelCase`` alias generator to individual models — any
|
|
serialization change must go through this base class so all models
|
|
update at once.
|
|
"""
|
|
|
|
model_config = ConfigDict(strict=True)
|
|
|
|
|
|
class PaginatedListResponse(BanGuiBaseModel, Generic[T]):
|
|
"""Standardized paginated list response.
|
|
|
|
Use this as a base for all endpoints that return paginated collections.
|
|
Automatically includes pagination metadata to support frontend paging UIs.
|
|
|
|
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.
|
|
|
|
Example:
|
|
```python
|
|
class UserListResponse(PaginatedListResponse[User]):
|
|
pass
|
|
|
|
# Returns:
|
|
{
|
|
"items": [...],
|
|
"total": 150,
|
|
"page": 2,
|
|
"page_size": 50
|
|
}
|
|
```
|
|
"""
|
|
|
|
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.")
|
|
|
|
|
|
class CollectionResponse(BanGuiBaseModel, Generic[T]):
|
|
"""Standardized non-paginated collection response.
|
|
|
|
Use this for endpoints that return a collection without pagination support.
|
|
Simpler than PaginatedListResponse, but still provides consistent wrapping.
|
|
|
|
Fields:
|
|
items: The data items in the collection.
|
|
total: Total number of items.
|
|
|
|
Example:
|
|
```python
|
|
class ActiveBansResponse(CollectionResponse[ActiveBan]):
|
|
pass
|
|
|
|
# Returns:
|
|
{
|
|
"items": [...],
|
|
"total": 42
|
|
}
|
|
```
|
|
"""
|
|
|
|
items: list[T] = Field(default_factory=list, description="Collection items.")
|
|
total: int = Field(..., ge=0, description="Total number of items.")
|
|
|
|
|
|
class CommandResponse(BanGuiBaseModel):
|
|
"""Standardized command/action result response.
|
|
|
|
Use this for endpoints that execute commands (start, stop, reload, ban, unban, etc.).
|
|
Always includes a success indicator and human-readable message.
|
|
|
|
Fields:
|
|
message: Human-readable result message or error description.
|
|
success: Whether the command succeeded (default True).
|
|
|
|
Example:
|
|
```python
|
|
class StartJailResponse(CommandResponse):
|
|
jail: str # Optional: target identifier
|
|
|
|
# Returns:
|
|
{
|
|
"message": "Jail 'sshd' started.",
|
|
"success": true,
|
|
"jail": "sshd"
|
|
}
|
|
```
|
|
"""
|
|
|
|
message: str = Field(..., description="Human-readable result or error message.")
|
|
success: bool = Field(
|
|
default=True,
|
|
description="Whether the command succeeded (false for errors in non-exception handlers).",
|
|
)
|