JSON decoding turns text into Python values; validating those values against an application schema is a separate step.
Python JSON validation: reject duplicate members and non-integer amounts
Operation contract
The receipt decoder uses an object-pairs hook to reject duplicate member names before a dictionary can overwrite them. It accepts exactly the amount_minor member and requires a positive integer, excluding bool. The program rejects both a boolean amount and two repeated amount members instead of letting each input become a plausible receipt.
Failure and ownership boundary
JSON input can consume memory before application validation runs, so cap incoming bytes or text before decoding. This fixture caps text length and accepts a flat one-field shape; it is not a general nested-document resource sandbox. Python strings and bytes: reject decoding errors before parsing records happens earlier, while Python dataclasses: frozen fields require an immutable value model can provide a later internal representation.
Working program
import json
def unique_members(pairs):
values = {}
for key, value in pairs:
if key in values:
raise ValueError("duplicate member")
values[key] = value
return values
def receipt_amount(text):
if len(text) > 1024:
raise ValueError("document too long")
values = json.loads(text, object_pairs_hook=unique_members)
if not isinstance(values, dict) or set(values) != {"amount_minor"}:
raise ValueError("receipt shape required")
amount = values["amount_minor"]
if type(amount) is not int or amount <= 0:
raise ValueError("positive integer amount required")
return amount
print(receipt_amount('{"amount_minor":125}'))
for payload in ['{"amount_minor":true}', '{"amount_minor":1,"amount_minor":2}']:
try:
receipt_amount(payload)
except ValueError:
print("document rejected")Output
125
document rejected
document rejectedCosts and limits
Decoding n bounded characters has input-proportional work and retains the decoded graph. The length cap does not define a general depth limit; deployments must choose broader limits for broader schemas.
Common Mistakes
- Parsing is not schema validation.
- Reject duplicate members before overwriting loses their evidence.
Connected lessons
Python dictionaries: insertion order and duplicate-key replacement, Python strings and bytes: reject decoding errors before parsing records, Python dataclasses: frozen fields require an immutable value model.
Apply this boundary
Flask JSON API: reject unknown fields, booleans and oversized bodies.
Related Python operation checks
Python tomllib: parse configuration and validate its schema, Mypy static checks: annotations do not validate runtime payloads.
Check the next state boundary
Python JSON Lines: cap line bytes and validate the whole batch before returning it.
Follow the service contract
Python HMAC envelopes: authenticate exact bytes and separate replay policy.
Follow the integrity boundary
Python JSON duplicate keys: reject ambiguous object fields, Python project: validate a JSONL batch before one SQLite commit.
