NV ToolkitFormat · Validate · Convert

Code Generators

JSON to Python Converter

Paste a JSON or XML sample — the format is auto-detected — and get typed Python models with names, nesting and nullability inferred for you.

In short

Convert JSON to Python online: paste a sample and generate typed Python models with serialization helpers — powered by quicktype, in your browser.

By NaveenKumar T · Updated

Learn: JSON Examples: From Hello World to Real API Payloads

  • JSON or XML input, auto-detected
  • Nested objects become types
  • Nullability inferred

Runs entirely in your browser — nothing you paste or open here is uploaded, logged, or stored.How we handle data →

Example

Example: JSON order payload to Python

A small order document with a nested object, an array of two items, a decimal total and a null field — enough to show how each Python type, list and nullable is inferred. The same page accepts the XML form of this order too, so the sample below is an example rather than the only accepted format. The right-hand side is the exact output of this tool.

Input · JSON
{
  "id": "ord_9F2KX",
  "status": "processing",
  "paid": true,
  "customer": { "name": "Ada Lovelace", "email": "ada@example.com", "phone": null },
  "items": [
    { "sku": "KB-75", "qty": 1, "price": 149.99 },
    { "sku": "MS-12", "qty": 2, "price": 39.5 }
  ],
  "total": 228.99
}
Generated · Python
from typing import Any, List, TypeVar, Callable, Type, cast


T = TypeVar("T")


def from_str(x: Any) -> str:
    assert isinstance(x, str)
    return x


def from_none(x: Any) -> Any:
    assert x is None
    return x


def from_int(x: Any) -> int:
    assert isinstance(x, int) and not isinstance(x, bool)
    return x


def from_float(x: Any) -> float:
    assert isinstance(x, (float, int)) and not isinstance(x, bool)
    return float(x)


def to_float(x: Any) -> float:
    assert isinstance(x, (int, float))
    return x


def from_bool(x: Any) -> bool:
    assert isinstance(x, bool)
    return x


def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
    assert isinstance(x, list)
    return [f(y) for y in x]


def to_class(c: Type[T], x: Any) -> dict:
    assert isinstance(x, c)
    return cast(Any, x).to_dict()


class Customer:
    name: str
    email: str
    phone: None

    def __init__(self, name: str, email: str, phone: None) -> None:
        self.name = name
        self.email = email
        self.phone = phone

    @staticmethod
    def from_dict(obj: Any) -> 'Customer':
        assert isinstance(obj, dict)
        name = from_str(obj.get("name"))
        email = from_str(obj.get("email"))
        phone = from_none(obj.get("phone"))
        return Customer(name, email, phone)

    def to_dict(self) -> dict:
        result: dict = {}
        result["name"] = from_str(self.name)
        result["email"] = from_str(self.email)
        result["phone"] = from_none(self.phone)
        return result


class Item:
    sku: str
    qty: int
    price: float

    def __init__(self, sku: str, qty: int, price: float) -> None:
        self.sku = sku
        self.qty = qty
        self.price = price

    @staticmethod
    def from_dict(obj: Any) -> 'Item':
        assert isinstance(obj, dict)
        sku = from_str(obj.get("sku"))
        qty = from_int(obj.get("qty"))
        price = from_float(obj.get("price"))
        return Item(sku, qty, price)

    def to_dict(self) -> dict:
        result: dict = {}
        result["sku"] = from_str(self.sku)
        result["qty"] = from_int(self.qty)
        result["price"] = to_float(self.price)
        return result


class Root:
    id: str
    status: str
    paid: bool
    customer: Customer
    items: List[Item]
    total: float

    def __init__(self, id: str, status: str, paid: bool, customer: Customer, items: List[Item], total: float) -> None:
        self.id = id
        self.status = status
        self.paid = paid
        self.customer = customer
        self.items = items
        self.total = total

    @staticmethod
    def from_dict(obj: Any) -> 'Root':
        assert isinstance(obj, dict)
        id = from_str(obj.get("id"))
        status = from_str(obj.get("status"))
        paid = from_bool(obj.get("paid"))
        customer = Customer.from_dict(obj.get("customer"))
        items = from_list(Item.from_dict, obj.get("items"))
        total = from_float(obj.get("total"))
        return Root(id, status, paid, customer, items, total)

    def to_dict(self) -> dict:
        result: dict = {}
        result["id"] = from_str(self.id)
        result["status"] = from_str(self.status)
        result["paid"] = from_bool(self.paid)
        result["customer"] = to_class(Customer, self.customer)
        result["items"] = from_list(lambda x: to_class(Item, x), self.items)
        result["total"] = to_float(self.total)
        return result


def root_from_dict(s: Any) -> Root:
    return Root.from_dict(s)


def root_to_dict(x: Root) -> Any:
    return to_class(Root, x)

Look for the "phone" field: sampled as null, it is typed as None. "items" became List[Item], and "total" is float.

Learn more

From JSON sample to Python types

Hand-writing model classes from a JSON payload is transcription work: read a field, type a property, repeat eighty times, miss one. This page runs quicktype (the same engine behind the best-known generators) against your document, merging array elements to find the common shape and naming nested types from their keys.

The from_dict helpers validate with assert, and python -O strips every assert from the compiled bytecode. Run the models under a normal interpreter, or replace the generated asserts with explicit "if not isinstance(...): raise TypeError" checks before shipping — otherwise a drifted payload passes silently in exactly the environment where the check was supposed to catch it.

How JSON values become Python types

Inference works from the values in your sample. Strings map to str, integers and decimals are told apart (228.99 becomes float, while 1 and 2 stay integral), true/false become the language's boolean, and an object such as "customer" becomes its own named type. The "items" array is typed as List[Item] because every element shares the same keys — quicktype unifies the shapes of all array elements into one Item type.

Nulls are the one place inference needs your help: "phone": null carries no type information, so the field is emitted as None. If the real API sometimes sends a string there, include a sample where the field is populated (paste several documents merged into one array) and the generated type becomes the union of what it saw.

Pasting XML works here too — a sample starting with "<" is parsed before inference runs — but if XML is your usual input, XML to Python is the page written for it: same generator, with the element-versus-attribute typing rules and a worked XML example.

Need models that validate themselves on construction rather than plain classes with a separate from_dict helper? JSON to Pydantic generates pydantic.BaseModel classes from the same kind of sample — the models FastAPI and most modern Python web services already expect.

Annotations, nulls and nested arrays in the generated Python

Python is annotation-free here: quicktype emits plain classes with class-level type hints, an explicit __init__, and from_dict/to_dict staticmethods — no dataclass decorator, no pydantic, no attrs. The real work sits in module-level helpers (from_str, from_int, from_float, from_none, from_list, from_union, to_class) that assert each value's type as they convert, so a drifted payload raises AssertionError at the field that broke rather than deep in your code. Wire names survive inside the helper calls: obj.get("customer-ref") feeds a customer_ref attribute, so PEP 8 naming costs you nothing.

A field sampled only as null is annotated None and converted with from_none, which asserts the value really is None — strict, and wrong the moment the API sends a string. Merge a second document where the field is populated and the hint becomes Optional[str], converted through from_union with both branches listed, which is the honest signature. A key missing from one of the merged samples gets the same Optional treatment plus an is-not-None guard in to_dict, so it is omitted from the output dict instead of being written back as null.

Nested objects become their own classes named from the key — Customer, Item — each with its own from_dict, and the parent calls them explicitly: Customer.from_dict(obj.get("customer")). A list of objects is hinted List[Item] and built with from_list(Item.from_dict, ...), so every element is validated, not just the first. The degenerate arrays are the thing to watch: one element is enough to name the class but not to reveal which fields are optional, and an empty array is hinted List[Any] with no element class generated at all.

Help

Frequently asked questions

Everything you need to know about the JSON to Python.

01How do I generate Python classes from JSON?

Paste a representative document — JSON or XML, the format is detected automatically — and press Convert. A real API response works best. Nested objects become their own Python types, arrays become List[Item], and the result downloads as Root.py.

02What does the generated Python code include?

Python output uses annotated classes with type hints and from_dict/to_dict helpers — modern, mypy-friendly models that make API payloads autocomplete in your editor.

03How do I use the generated Python code in my project?

Nothing to install — the output is standard-library Python 3 (typing plus explicit __init__ constructors). Parse with root_from_dict(json.loads(text)) and serialize with root_to_dict(root); every class also exposes from_dict and to_dict. The helpers assert each value's type as they convert, so a payload that drifts from the sample fails loudly with an AssertionError instead of silently producing a wrong object.

04Does the generated Python require any dependencies?

The output is standard library only — typing, plus datetime and enum where the sample needs them — so nothing extra needs installing. The from_dict helpers do the casting explicitly, so you also get a readable map of how each field converts.

Keep working

Related tools

Learn the format

Related guides

All guides →