DevToolsmith

JSON to Pydantic Model Converter

Paste JSON to generate Pydantic v2 models, ready for FastAPI or any Python project. Detects datetime, UUID and URL fields, optional and nullable values, and can convert camelCase keys to snake_case with aliases.

Runs 100% in your browser — nothing is uploaded

JSON
Tip: drop a file here361 chars · 361 bytes · 14 lines
Pydantic models
534 chars · 534 bytes · 29 lines

Tip: paste an array of several objects — keys missing from some of them become optional (= None).

Example

JSON input
{
  "id": "a3f1c2d4-5b6e-4f70-8a9b-0c1d2e3f4a5b",
  "displayName": "Noor",
  "createdAt": "2026-02-01T12:00:00Z",
  "homepage": "https://noor.dev",
  "settings": {
    "theme": "dark",
    "beta": false
  },
  "sessions": [
    {
      "device": "laptop",
      "lastSeen": "2026-10-20T08:15:00Z"
    },
    {
      "device": "phone",
      "lastSeen": null,
      "pushToken": "tok_1"
    }
  ]
}
Generated models (snake_case fields enabled)
from datetime import datetime
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, HttpUrl


class Settings(BaseModel):
    theme: str
    beta: bool


class Session(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    device: str
    last_seen: datetime | None = Field(alias="lastSeen")
    push_token: str | None = Field(default=None, alias="pushToken")


class Account(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    id: UUID
    display_name: str = Field(alias="displayName")
    created_at: datetime = Field(alias="createdAt")
    homepage: HttpUrl
    settings: Settings
    sessions: list[Session]

Nested models are defined before the models that reference them, so the file runs as-is. pushToken exists in only one session, so it's optional with a default of None. lastSeen is always present but sometimes null, so it's nullable but still required.

Using the model

Validating an API response

import httpx
from pydantic import ValidationError

resp = httpx.get("https://api.example.com/me")
try:
    account = Account.model_validate(resp.json())
except ValidationError as e:
    print(e.errors())        # field-by-field details
else:
    print(account.display_name, account.created_at.year)

# Serialize using the original JSON keys
account.model_dump(by_alias=True, mode="json")

As a FastAPI request and response body

from fastapi import FastAPI

app = FastAPI()

@app.post("/accounts")
def create_account(account: Account) -> Account:
    # FastAPI validates the request body against the model
    return account

Type mapping

JSON valuePython / Pydantic type
stringstr
ISO 8601 date-time / datedatetime / date
UUID stringUUID
http(s) URLHttpUrl
emailEmailStr (needs pydantic[email])
integer / decimalint / float
true / falsebool
objectnested BaseModel
arraylist[T]
mixed typesint | str

Turn off Detect formats to keep every string as plain str. Pick the List[str], Optional style if you need to support Python 3.8 or 3.9.

Field names that need care

  • Python keywords such as class or from become class_ and from_, with an alias.
  • Pydantic treats names starting with _ as private, so _id becomes id with an alias.
  • Keys with spaces or dashes are converted to valid identifiers with an alias.

Building the frontend too? Generate TypeScript interfaces or a Zod schema from the same payload.

Frequently asked questions

How do I generate a Pydantic model from JSON?

Paste a JSON sample into the tool above. It creates a BaseModel subclass for every object, infers int, float, bool, str, list and nested model types, detects datetime, UUID and URL strings, and marks fields that are missing or null in some samples as optional.

Is the output Pydantic v1 or v2?

Pydantic v2: it uses model_config = ConfigDict(...) and RootModel. For older projects the field definitions mostly work in v1 too, but replace ConfigDict with an inner class Config and RootModel with __root__.

How do I keep camelCase JSON keys but use snake_case in Python?

Enable "snake_case fields". Each field is renamed to snake_case and gets Field(alias="originalKey"), so validation reads the camelCase key. populate_by_name=True also lets you construct the model with Python names. Use model_dump(by_alias=True) to write the original keys back.

What is the difference between Optional fields and nullable fields?

A key missing from some samples becomes x: T | None = None, so it is not required. A key that is always present but sometimes null becomes x: T | None with no default, so it must be present but may be None.

Why does a field use Any?

Its value was null in every sample, or it was an empty list, so the real type can’t be inferred. Replace Any with the correct type once you know it.