Interview frequency: …
Short answer
Parse the text with json.loads, then validate the shape and types at the boundary, then convert it to a trusted internal model before using it in application logic.
Explanation
json.loads only guarantees that the text is valid JSON; it does not guarantee the fields, their types, or business rules. Separate three steps: parsing (which may raise JSONDecodeError), then validation (missing fields or wrong types), then mapping to the domain model. Return errors that distinguish malformed JSON from an incomplete payload. Note that json converts decimal numbers to float, so use parse_float=Decimal for monetary amounts.
Code example
import json
from decimal import Decimal
def parse_payment(body: str) -> Payment:
try:
data = json.loads(body, parse_float=Decimal)
except json.JSONDecodeError as err:
raise BadRequest("malformed JSON") from err
if not isinstance(data, dict) or "amount" not in data:
raise BadRequest("amount is required")
return Payment(amount=Decimal(data["amount"]), currency=data.get("currency", "EGP"))Common mistakes
- Using float for monetary amounts coming from JSON.
- Accessing data["field"] directly without validation, so a KeyError surfaces as a 500 error.