Problem
Currently, the API only supports PUT operations for updating player data, which requires sending the entire player object even when only one or two fields need to be modified. This is inefficient and doesn't follow REST best practices for partial resource updates. Users need a way to update specific player fields without having to provide all player data.
Proposed Solution
Implement HTTP PATCH method endpoints to allow partial updates of player resources. The API should accept a PlayerPartialUpdateRequest model and update only the fields provided in the request, leaving other fields unchanged.
Important constraint: Partial updates should allow modifying team-related data (position, squad number, team, league) but NOT personal details (firstName, middleName, lastName, dateOfBirth). Personal information should only be modified via PUT (full update).
Endpoint to implement:
PATCH /players/squadnumber/{squad_number} - Update specific fields of a player by squad number
Note: We use squad number (natural identifier) instead of internal ID, as squad numbers are unique and user-facing.
Suggested Approach
1. Route Definition (routes/player_route.py)
- Add
@api_router.patch("/players/squadnumber/{squad_number}") endpoint
- Include cache invalidation (call
await simple_memory_cache.clear(CACHE_KEY))
- Add appropriate status codes (200 for success, 404 for not found, 400 for validation errors, 409 for conflicts)
2. Service Layer (services/player_service.py)
- Create
async def patch_player_by_squad_number(async_session: AsyncSession, squad_number: int, update_data: dict) -> Optional[Player]
- If updating squad_number field itself, validate new squad_number doesn't create duplicates
- Handle partial data using
exclude_unset=True in Pydantic model serialization
3. Model Definition (models/player_model.py)
-
Refactor existing PlayerModel class to support Request/Response pattern with data transformations
-
Create PlayerResponse class (for GET operations) with transformed properties to demonstrate data mapping:
class PlayerResponse(BaseModel):
full_name: str = Field(alias="fullName") # Computed from firstName + middleName + lastName
birth: str # Formatted date string from dateOfBirth
dorsal: int # Maps from squadNumber (different naming)
position: str
club: str # Maps from team (different naming)
league: str
starting11: str # Transformed from bool to "Yes"/"No" string
@field_validator('full_name', mode='before')
@classmethod
def compute_full_name(cls, v, info):
# Compute from firstName, middleName, lastName in entity
pass
-
Create PlayerCreateRequest class (for POST - all fields except id)
-
Create PlayerUpdateRequest class (for PUT - full replacement, all fields except id)
-
Create PlayerPartialUpdateRequest class with only team-related fields as Optional:
squad_number: Optional[int]
position: Optional[str]
abbr_position: Optional[str]
team: Optional[str]
league: Optional[str]
starting11: Optional[bool]
- Excludes: firstName, middleName, lastName, dateOfBirth (personal details)
-
Implement mapper function or use Pydantic @computed_field to transform entity to response:
- Concatenate firstName, middleName, lastName → fullName
- Format dateOfBirth → birth (ISO date string)
- Rename squadNumber → dorsal
- Rename team → club
- Convert starting11 bool → "Yes"/"No" string
-
All models maintain camelCase aliasing with to_camel function
-
Add appropriate validators for fields that require validation (e.g., squad number uniqueness)
4. Testing (tests/test_main.py)
- Test partial updates (single field, multiple fields)
- Test squad number uniqueness validation during PATCH
- Test 404 response for non-existent player
- Test cache invalidation after PATCH operations
- Use test data from
player_stub.py
5. Code Style
- Format with Black:
black .
- Lint with flake8:
flake8
- Follow async/await patterns consistently
- Add proper type hints for all function parameters and return values
Acceptance Criteria
References
Problem
Currently, the API only supports PUT operations for updating player data, which requires sending the entire player object even when only one or two fields need to be modified. This is inefficient and doesn't follow REST best practices for partial resource updates. Users need a way to update specific player fields without having to provide all player data.
Proposed Solution
Implement HTTP PATCH method endpoints to allow partial updates of player resources. The API should accept a
PlayerPartialUpdateRequestmodel and update only the fields provided in the request, leaving other fields unchanged.Important constraint: Partial updates should allow modifying team-related data (position, squad number, team, league) but NOT personal details (firstName, middleName, lastName, dateOfBirth). Personal information should only be modified via PUT (full update).
Endpoint to implement:
PATCH /players/squadnumber/{squad_number}- Update specific fields of a player by squad numberNote: We use squad number (natural identifier) instead of internal ID, as squad numbers are unique and user-facing.
Suggested Approach
1. Route Definition (
routes/player_route.py)@api_router.patch("/players/squadnumber/{squad_number}")endpointawait simple_memory_cache.clear(CACHE_KEY))2. Service Layer (
services/player_service.py)async def patch_player_by_squad_number(async_session: AsyncSession, squad_number: int, update_data: dict) -> Optional[Player]exclude_unset=Truein Pydantic model serialization3. Model Definition (
models/player_model.py)Refactor existing
PlayerModelclass to support Request/Response pattern with data transformationsCreate
PlayerResponseclass (for GET operations) with transformed properties to demonstrate data mapping:Create
PlayerCreateRequestclass (for POST - all fields except id)Create
PlayerUpdateRequestclass (for PUT - full replacement, all fields except id)Create
PlayerPartialUpdateRequestclass with only team-related fields as Optional:squad_number: Optional[int]position: Optional[str]abbr_position: Optional[str]team: Optional[str]league: Optional[str]starting11: Optional[bool]Implement mapper function or use Pydantic
@computed_fieldto transform entity to response:All models maintain camelCase aliasing with
to_camelfunctionAdd appropriate validators for fields that require validation (e.g., squad number uniqueness)
4. Testing (
tests/test_main.py)player_stub.py5. Code Style
black .flake8Acceptance Criteria
PlayerResponsefor GET operations with computed/transformed fields (fullName, birth, dorsal, club, starting11 as string)PlayerCreateRequestfor POST operationsPlayerUpdateRequestfor PUT operationsPlayerPartialUpdateRequestfor PATCH operations (excludes personal details)/players/squadnumber/{squad_number}successfully updates team-related player fieldspytest -v/docsReferences