No canonical snake_case/camelCase serialization policy
This commit is contained in:
@@ -465,18 +465,14 @@ class BansByCountryResponse(BaseModel):
|
||||
|
||||
## 5. Pydantic Models
|
||||
|
||||
- Every model inherits from `pydantic.BaseModel`.
|
||||
- Use `model_config = ConfigDict(strict=True)` where appropriate.
|
||||
- Field names use **snake_case** in Python, export as **camelCase** to the frontend via alias generators if needed.
|
||||
- Validate at the boundary — once data enters a Pydantic model it is trusted.
|
||||
- Use `Field(...)` with descriptions for every field to keep auto-generated docs useful.
|
||||
- Separate **request models**, **response models**, and **domain (internal) models** — do not reuse one model for all three.
|
||||
### Base Class
|
||||
|
||||
Every model in `app/models/` **must** inherit from `BanGuiBaseModel` (defined in `app/models/response.py`), not from `pydantic.BaseModel` directly.
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
from app.models.response import BanGuiBaseModel
|
||||
|
||||
class BanResponse(BaseModel):
|
||||
class BanResponse(BanGuiBaseModel):
|
||||
ip: str = Field(..., description="Banned IP address")
|
||||
jail: str = Field(..., description="Jail that issued the ban")
|
||||
banned_at: datetime = Field(..., description="UTC timestamp of the ban")
|
||||
@@ -484,6 +480,24 @@ class BanResponse(BaseModel):
|
||||
ban_count: int = Field(..., ge=1, description="Number of times this IP was banned")
|
||||
```
|
||||
|
||||
`BanGuiBaseModel` sets `strict=True` and documents the naming policy. Do **not** override `model_config` on individual models unless you have a specific, documented reason.
|
||||
|
||||
### API Field Naming Policy — snake_case everywhere
|
||||
|
||||
All API field names use **`snake_case`** in Python, in the JSON wire format, and in the corresponding TypeScript interfaces. There is no `alias_generator` that converts to camelCase.
|
||||
|
||||
- ✅ Python field: `active_jails` → JSON key: `"active_jails"` → TypeScript property: `active_jails`
|
||||
- ❌ Do **not** add a camelCase `alias_generator` to individual models.
|
||||
- ❌ Do **not** mix field name conventions within a single API response.
|
||||
|
||||
This policy eliminates a whole class of frontend–backend contract bugs. If the naming policy ever needs to change (e.g. to emit camelCase), change `BanGuiBaseModel` once — all models update automatically.
|
||||
|
||||
### Other Model Rules
|
||||
|
||||
- Validate at the boundary — once data enters a Pydantic model it is trusted.
|
||||
- Use `Field(...)` with descriptions for every field to keep auto-generated docs useful.
|
||||
- Separate **request models**, **response models**, and **domain (internal) models** — do not reuse one model for all three.
|
||||
|
||||
### Using `Literal` Types for Constrained Strings
|
||||
|
||||
When a field should only accept a small set of predefined values, use `Literal` to enforce this at the type level:
|
||||
|
||||
Reference in New Issue
Block a user