Skip to content

require-pydantic-for-external-json

Proven external JSON record fields are consumed before runtime schema validation.

Why

Annotations, casts, and partial key checks do not validate a wire protocol; a maintained runtime schema makes required fields, types, and protocol versions explicit at the boundary.

Fix

Validate raw JSON with Model.model_validate_json(...); use a named RootModel for scalar or collection roots. For an already-decoded response, use model_validate or another maintained runtime schema validator before reading fields.

Examples

Before — flagged A local factory forwards an unvalidated response
protocol.py
import httpx
class Envelope:
def __init__(self, body):
self.body = body
def payload(self):
return self.body
def wrap(body):
result = Envelope(body)
return result
def fetch():
raw = httpx.get("https://api.example/report").json()
return wrap(raw).payload()["version"]
After — preferred A factory receives a locally constructed record
protocol.py
import httpx
class Envelope:
def __init__(self, body):
self.body = body
def payload(self):
return self.body
def wrap(body):
return Envelope(body)
def fetch():
remote = httpx.get("https://api.example/report").json()
return wrap({"version": 1}).payload()["version"]
Before — flagged External JSON read as a dictionary
protocol.py
import httpx
def fetch() -> object:
report = httpx.get("https://api.example/report").json()
return report.get("version")
After — preferred External JSON validated by a boundary model
protocol.py
import httpx
from pydantic import BaseModel
class Report(BaseModel):
version: int
def fetch() -> Report:
raw = httpx.get("https://api.example/report").json()
report = Report.model_validate(raw)
return report