[JSONZen]
Sign up and get Pro free for 3 months — no card required.Claim it →

Conversion guide

JSON to Pydantic: Generate Python Models

Generate Pydantic v2 models from a JSON sample for runtime validation in Python. Handles nested objects, optional fields, and Optional vs Union types.

Python services that consume JSON — FastAPI handlers, Celery message workers, anything that touches an external API — need a strict parser at the boundary. Pydantic is the default choice, but writing a model for a 100-field payload by hand is tedious and error-prone. Generating one from a real sample is faster and lines up exactly with the wire format.

Paste a sample into the JSON to Pydantic generator for instant output, or read on for the structural rules.

TL;DR

A JSON to Pydantic converter maps each JSON value to a typed field on a BaseModel: objects become nested models, arrays become list[T], primitives map directly. Multiple samples widen fields to Optional[T] = None where the field can be missing. Pydantic v2 syntax — model_config, Field, and Annotated — is the default.

Step 1 — Flat primitives

{
  "id": "u_001",
  "name": "Otter",
  "email": "otter@example.com",
  "is_admin": false
}
from pydantic import BaseModel

class User(BaseModel):
    id: str
    name: str
    email: str
    is_admin: bool

Pydantic preserves the JSON snake_case keys verbatim. If your Python style demands camelCase or aliases, configure that with Field(alias=...):

from pydantic import BaseModel, ConfigDict, Field

class User(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    id: str
    name: str
    email: str
    is_admin: bool = Field(alias="isAdmin")

Step 2 — Nested models

Nested JSON objects become nested classes. Extract them by name so they can be referenced elsewhere.

{
  "id": "ord_A100",
  "customer": {
    "name": "Company A",
    "country": "US"
  },
  "shipping": {
    "city": "Springfield",
    "zip": "00000"
  }
}
from pydantic import BaseModel

class Customer(BaseModel):
    name: str
    country: str

class Shipping(BaseModel):
    city: str
    zip: str

class Order(BaseModel):
    id: str
    customer: Customer
    shipping: Shipping

Order matters: nested types must be declared before the model that uses them. The generator emits them in that order automatically.

Step 3 — Arrays

Arrays map to list[T]. Mixed-element arrays widen to a union.

{
  "tags": ["new", "featured"],
  "items": [
    { "sku": "widget", "qty": 2 },
    { "sku": "gadget", "qty": 5 }
  ]
}
from pydantic import BaseModel

class Item(BaseModel):
    sku: str
    qty: int

class Payload(BaseModel):
    tags: list[str]
    items: list[Item]

For a union of primitives — ["a", 1, true] — the field becomes list[str | int | bool]. Most of the time that's a smell in the source data, not a real requirement.

Step 4 — Optional and nullable

Pydantic distinguishes "field can be missing" from "field is present but can be None". The first uses a default; the second uses Optional (or T | None).

Input (multiple samples)

[
  { "id": "u_001", "email": "otter@example.com" },
  { "id": "u_002", "email": null },
  { "id": "u_003", "email": "lynx@example.com", "verified_at": "2026-01-15" }
]

Output

from pydantic import BaseModel

class User(BaseModel):
    id: str
    email: str | None
    verified_at: str | None = None

email is required but can be None. verified_at can be absent — Python sees None if not supplied. With one sample only, every field is required and non-nullable; feed several samples whenever possible.

Step 5 — Validate at the boundary

The point of generating a Pydantic model is to actually use it for parsing. Two patterns:

# Throws ValidationError on any mismatch.
user = User.model_validate(payload_dict)

# JSON in, model out — handy in FastAPI handlers.
user = User.model_validate_json(raw_bytes)

For FastAPI, declaring the model as a handler parameter does the parsing automatically and returns a 422 with a structured error list when it fails:

@app.post("/users")
def create_user(user: User) -> User:
    return user

For non-Python consumers, generate a matching JSON Schema so other services can validate the same payload.

Common conversion problems

"Pydantic says 'Input should be a valid string' but the value is a number"

The JSON had "price": 19.99 and your generated model declared price: str. Pydantic v2 is strict about types by default — it does not coerce silently. Either fix the type or annotate the field with coerce_numbers_to_str=True in the config.

"Optional field is required at runtime"

x: int | None declares the type as nullable but the field as required. To make it optional, add a default: x: int | None = None.

"Datetime strings won't parse"

Use datetime from the standard library — Pydantic v2 parses ISO 8601 strings into datetime automatically when the field type is datetime. The generator emits str from a JSON sample because it can't know the field is a timestamp; switch the type after generation.

"Extra fields appear in my output JSON"

Pydantic ignores unknown keys on input by default, but doesn't drop fields when re-serializing. Configure model_config = ConfigDict(extra="forbid") to reject unknown keys at the boundary.

"I want one model to accept multiple shapes"

Use a discriminated union with Field(discriminator='type'). The generator emits a single model — you'll need to refactor it into a union by hand if the API actually has variants.

Generate in the browser, no upload

The free JSON to Pydantic generator on JSONZen emits a complete Pydantic v2 model with nested classes, optional fields, and proper types. It runs entirely in your browser and never sends your data anywhere.

For TypeScript consumers of the same API, generate a matching TypeScript interface from the same sample so both sides stay in sync.

Closing recommendation

Generate the Pydantic model from a real sample, paste it into your service, and call model_validate_json at every boundary. The strictness of Pydantic v2 catches API drift the moment it ships — and is friendlier than discovering the issue in a downstream KeyError six functions later.

Related guides

Related tools