Python JSON Dates and Decimals: Serialize Values Deliberately
Python can serialize strings, numbers, lists, dictionaries, booleans and None with its standard JSON module. Some useful application values do not have a direct JSON counterpart. Dates, times, decimals, UUIDs and custom classes require an explicit decision about their representation before they cross an API or file boundary.
JSON has a limited type system
JSON has no built-in date, decimal or binary type. A date is commonly represented as a text string, and a monetary or score-like amount may be represented as a string or an integer count of smaller units. The best choice depends on the receiving system and must be agreed upon by both sides of the interface.
A real bug: numbers turning into strings between the database and the API
I hit a version of this typing problem on the PHP side of my own backend, and it is worth knowing about even if you work in Python, because the same class of bug shows up with any database driver. PHP's PDO returns database columns as strings by default — an integer column like level comes back as the PHP string "27", not the number 27. If that value goes straight into json_encode(), the API response contains "level": "27" — a quoted string — instead of "level": 27.
That is exactly why every field in my leaderboard and progress endpoints gets an explicit cast before encoding:
echo json_encode([
'level' => (int)$p['level'],
'xp' => (int)$p['xp'],
'effortScore' => (int)$p['effort_score'],
]);
Skip the cast and the bug is easy to miss during manual testing — the value still displays correctly in a browser or Postman. It breaks downstream, in whatever client code expects a number and instead gets a string: a sort function that behaves like alphabetical sort instead of numeric, or a Python client doing arithmetic on "27" and getting a TypeError instead of silently producing the wrong number.
Use a documented date format
An ISO 8601-style string with an explicit time zone is generally easier to compare and exchange than a locale-specific date. Decide whether a value represents a date only, a local time or a precise timestamp. Store enough information to recover the intended meaning; a timestamp without a time-zone convention invites errors.
Do not silently turn Decimal into float
Binary floating-point values can introduce small rounding differences. For money and exact quantities, decide whether JSON will carry a quoted decimal string or an integer such as cents. Convert intentionally and validate the value on the receiving side rather than relying on a generic fallback serializer.
Round-trip test important values
Serialize a representative value, read it back and compare the normalized result with what the application expects. For dates this might mean comparing an aware timestamp; for currency or score fields it might mean confirming the type survived, not just the number. Tests should document accepted precision, time-zone behavior, and expected types.
Related reading
Continue with json.dumps and json.loads and the Python dictionary to JSON guide. Technical examples are a starting point for understanding a format; the documentation for the software you use remains the final reference.