Python
JSON
Serialize
Decimal
Data Serialization

Python JSON serialize a Decimal object

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Python Decimal is essential for precise values such as money, but the built-in json module does not serialize it by default. This mismatch causes runtime errors when API payloads include decimal fields. A good solution defines one consistent conversion policy and applies it at system boundaries.

Why Default json.dumps Fails

json.dumps supports only standard JSON-compatible Python types. Decimal is not one of them.

python
1import json
2from decimal import Decimal
3
4payload = {"amount": Decimal("12.34")}
5# json.dumps(payload)  # raises TypeError

You must convert Decimal explicitly before encoding.

Quick Solution with default

Use default callback for one-off serialization.

python
1import json
2from decimal import Decimal
3
4payload = {"amount": Decimal("12.34"), "tax": Decimal("1.66")}
5
6text = json.dumps(
7    payload,
8    default=lambda obj: str(obj) if isinstance(obj, Decimal) else obj,
9)
10
11print(text)

Converting to string preserves exact decimal representation.

Reusable Encoder Class

For larger codebases, prefer a custom encoder class.

python
1import json
2from decimal import Decimal
3
4class DecimalEncoder(json.JSONEncoder):
5    def default(self, obj):
6        if isinstance(obj, Decimal):
7            return str(obj)
8        return super().default(obj)
9
10payload = {"net": Decimal("99.95")}
11print(json.dumps(payload, cls=DecimalEncoder))

This keeps behavior consistent across services.

Choose String Versus Float Policy

Two common policies:

  1. Serialize as string for precision safety.
  2. Serialize as float for client convenience.

Float conversion may lose precision.

python
from decimal import Decimal
print(float(Decimal("0.1")))

For finance, string policy is usually safer.

Parse Back to Decimal on Read

If JSON stores decimal as string, decode intentionally.

python
1import json
2from decimal import Decimal
3
4text = '{"amount": "12.34"}'
5obj = json.loads(text)
6amount = Decimal(obj["amount"])
7print(amount, type(amount))

Round-trip behavior becomes explicit and testable.

Decode Numeric JSON to Decimal

If incoming JSON contains numeric tokens, parse_float helps.

python
1import json
2from decimal import Decimal
3
4text = '{"amount": 12.34}'
5obj = json.loads(text, parse_float=Decimal)
6print(obj["amount"], type(obj["amount"]))

This avoids binary float conversion during decode.

Apply Conversion at Boundaries Only

Keep Decimal in domain logic and convert only when crossing boundaries such as HTTP responses, message queues, or file export. Boundary-only conversion reduces accidental precision loss in internal calculations.

A clean architecture is:

  • Domain layer uses Decimal.
  • Serialization layer converts according to contract.
  • Clients parse according to contract.

Define API Contract Clearly

If decimals are serialized as strings, document that in schema and examples.

Example payload:

python
1invoice = {
2    "currency": "USD",
3    "amount": "123.45",
4    "scale": 2,
5}

Documenting scale and format avoids client-side ambiguity.

Nested Structure Handling

Real payloads often contain decimals inside nested dictionaries and lists. A centralized encoder handles this naturally because conversion is applied recursively during encoding.

python
payload = {\"items\": [{\"price\": Decimal(\"1.25\")}, {\"price\": Decimal(\"2.50\")}]}
print(json.dumps(payload, cls=DecimalEncoder))

This prevents partial fixes where top-level decimals are handled but nested ones still fail.

Testing Strategy

Add tests for nested objects, negative values, high precision values, and zero-scale values.

python
1from decimal import Decimal
2import json
3
4text = json.dumps({"x": Decimal("1.00")}, cls=DecimalEncoder)
5assert text == '{"x": "1.00"}'

Contract-focused tests prevent silent behavior drift after refactors.

Common Pitfalls

  • Converting Decimal to float without precision review.
  • Using different conversion rules across endpoints.
  • Forgetting nested decimal fields in lists and dictionaries.
  • Omitting parse strategy on the consumer side.
  • Not documenting decimal format in API contracts.

Summary

  • Built-in JSON encoding does not handle Decimal automatically.
  • Use default callbacks or custom encoders consistently.
  • Prefer string encoding when exact precision matters.
  • Decode with explicit decimal parsing rules.
  • Keep conversion logic at system boundaries and enforce with tests.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.