Working with an API that returns JSON? Instead of writing Python classes by hand and guessing field types from the docs, paste the response and get typed data classes generated instantly.
Generate Python dataclasses from JSON →
Why Typed Python Classes Matter
The old pattern of using raw dictionaries for API responses is fragile:
# Dictionary access — no type hints, no autocomplete, runtime KeyError risks
user = response.json()
print(user['profile']['name']) # What if 'profile' is None?
print(user['age'] + 1) # What if 'age' is a string?
Python dataclasses, Pydantic models, and TypedDict all solve this by giving you:
- Autocomplete in IDEs
- Type checker support (mypy, pyright)
- Clear documentation of data shape
- Explicit handling of optional fields
Three Output Modes
The tool supports three output formats, each suited to a different use case.
@dataclass (stdlib, default)
Standard library, no dependencies. Best for internal data structures, configuration, and when you want zero overhead:
from dataclasses import dataclass
from typing import List, Optional, Any
@dataclass
class Address:
street: str
city: str
zip_code: Optional[str] = None
@dataclass
class User:
id: int
name: str
email: str
address: Address
tags: List[str]
avatar: Optional[Any] = None
Pydantic v2 BaseModel
Best for API validation, settings management, and anywhere you need runtime validation plus serialization. Pydantic is the standard choice for FastAPI applications:
from pydantic import BaseModel
from typing import List, Optional, Any
class Address(BaseModel):
street: str
city: str
zip_code: Optional[str] = None
class User(BaseModel):
id: int
name: str
email: str
address: Address
tags: List[str]
avatar: Optional[Any] = None
With Pydantic, you get validation on instantiation, .model_dump() for serialization, and .model_validate() for parsing dictionaries.
TypedDict (Python 3.8+)
Best for type-checking dictionaries without changing their runtime behavior. Useful when working with libraries that expect plain dicts:
from typing import List, Optional, Any, TypedDict
class Address(TypedDict):
street: str
city: str
zip_code: Optional[str]
class User(TypedDict):
id: int
name: str
email: str
address: Address
tags: List[str]
avatar: Optional[Any]
JSON Type to Python Type Mapping
| JSON | Python |
|---|---|
"string" | str |
42 | int |
3.14 | float |
true / false | bool |
null | Optional[Any] = None |
["a", "b"] | List[str] |
[1, "a", true] mixed | List[Union[int, str, bool]] |
{} nested object | separate class |
How Nested Objects Are Handled
Each nested object becomes its own named class in PascalCase, derived from the field name. Classes are always output in dependency order — children before parents — so the generated code is immediately usable without rearranging:
Input JSON:
{
"user": {
"profile": {
"bio": "Developer",
"location": "Berlin"
},
"name": "Alice",
"age": 30
},
"timestamp": 1713456789
}
Generated @dataclass:
from dataclasses import dataclass
from typing import Any
@dataclass
class Profile:
bio: str
location: str
@dataclass
class User:
profile: Profile
name: str
age: int
@dataclass
class Root:
user: User
timestamp: int
Optional Fields and Nullable Values
A field is marked Optional when:
- Its value is
nullin the sample JSON - It is absent in some objects within a JSON array
# JSON: {"score": null, "grade": "A"}
# score is null → Optional[Any] = None
@dataclass
class Result:
grade: str
score: Optional[Any] = None
When processing arrays of objects, the tool merges all fields from all items. Fields that only appear in some items become Optional.
Working with API Responses
FastAPI + Pydantic
The most common use case is parsing FastAPI endpoint responses:
import httpx
from pydantic import BaseModel
from typing import List
class Post(BaseModel):
id: int
title: str
body: str
userId: int
class Comment(BaseModel):
postId: int
id: int
name: str
email: str
body: str
# Parse API response into typed models
async with httpx.AsyncClient() as client:
resp = await client.get('https://api.example.com/posts/1')
post = Post.model_validate(resp.json())
print(post.title) # fully typed
Standard @dataclass with dacite
If you prefer stdlib dataclasses but still want dict → dataclass conversion:
from dacite import from_dict
from dataclasses import dataclass
@dataclass
class User:
id: int
name: str
email: str
data = {"id": 1, "name": "Alice", "email": "[email protected]"}
user = from_dict(User, data)
print(user.name) # Alice
TypedDict with json.loads
For zero-overhead type checking of JSON data:
import json
from typing import TypedDict, cast
class Config(TypedDict):
host: str
port: int
debug: bool
with open('config.json') as f:
config: Config = cast(Config, json.load(f))
print(config['host']) # type-checked by mypy/pyright
Customizing the Root Class Name
By default the top-level class is named Root. Change it to match your domain:
- API response →
ApiResponse,SearchResult,UserProfile - Configuration file →
AppConfig,DatabaseConfig - Webhook payload →
WebhookEvent,PaymentNotification
The tool propagates your root class name through the output consistently.
Limitations to Know
JSON is a sample, not a schema. If a field can be multiple types in practice, the tool only sees the type in your sample. Always review Optional fields and union types before production use.
Naming comes from field keys. The tool converts snake_case, camelCase, and kebab-case JSON keys to PascalCase class names. Unusual naming patterns may produce unexpected class names — rename in the output as needed.
Deep nesting creates many classes. Deeply nested JSON produces a class hierarchy of the same depth. This is correct behavior, not a bug.
Related Tools
- JSON to TypeScript → — generate TypeScript interfaces from JSON
- JSON to Go Struct → — generate Go structs from JSON
- JSON Formatter → — pretty-print and validate JSON before converting
Paste your JSON and pick your output format. Open the JSON to Python Dataclass generator →