diff --git a/models/player_model.py b/models/player_model.py index 100cb39..aa85389 100644 --- a/models/player_model.py +++ b/models/player_model.py @@ -5,6 +5,15 @@ - `PlayerRequestModel`: Represents player data for Create and Update operations. - `PlayerResponseModel`: Represents player data including UUID for Retrieve operations. +Design decision — single request model vs split models: + A single `PlayerRequestModel` is intentionally shared by both POST (Create) + and PUT (Update). Per-operation differences are handled at the route layer + rather than by duplicating the model: + - POST checks that `squad_number` does not already exist (→ 409 Conflict). + - PUT checks that `squad_number` in the body matches the path parameter + (→ 400 Bad Request), ensuring the request is unambiguous. The path + parameter is always the authoritative source of identity on PUT. + These models are used for data validation and serialization in the API. """ diff --git a/routes/player_route.py b/routes/player_route.py index 4e50d66..631e511 100644 --- a/routes/player_route.py +++ b/routes/player_route.py @@ -199,9 +199,14 @@ async def put_async( async_session (AsyncSession): The async version of a SQLAlchemy ORM session. Raises: + HTTPException: HTTP 400 Bad Request if squad_number in the request body does + not match the path parameter. The path parameter is the authoritative source + of identity on PUT; a mismatch makes the request ambiguous. HTTPException: HTTP 404 Not Found error if the Player with the specified Squad Number does not exist. """ + if player_model.squad_number != squad_number: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST) player = await player_service.retrieve_by_squad_number_async( async_session, squad_number ) diff --git a/tests/test_main.py b/tests/test_main.py index 6ac99be..9ed2f73 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -234,6 +234,20 @@ def test_request_put_player_squadnumber_existing_response_status_no_content(clie assert response.status_code == 204 +def test_request_put_player_squadnumber_mismatch_response_status_bad_request(client): + """PUT /players/squadnumber/{squad_number} with mismatched squad number in body returns 400 Bad Request""" + # Arrange + squad_number = existing_player().squad_number + player = existing_player() + player.squad_number = unknown_player().squad_number + # Act + response = client.put( + PATH + "squadnumber/" + str(squad_number), json=player.__dict__ + ) + # Assert + assert response.status_code == 400 + + # DELETE /players/squadnumber/{squad_number} -----------------------------------