JSON을 반환하는 API를 사용하고 있나요? 문서에서 필드 타입을 추측하며 Python 클래스를 손으로 작성하는 대신, 응답을 붙여넣으면 타입이 있는 데이터 클래스가 즉시 생성됩니다.
타입이 있는 Python 클래스가 중요한 이유
API 응답에 원시 딕셔너리를 사용하는 오래된 패턴은 취약합니다:
# 딕셔너리 접근 — 타입 힌트 없음, 자동완성 없음, 런타임 KeyError 위험
user = response.json()
print(user['profile']['name']) # 'profile'이 None이라면?
print(user['age'] + 1) # 'age'가 문자열이라면?
Python dataclass, Pydantic 모델, TypedDict는 모두 이를 해결합니다:
- IDE에서 자동완성
- 타입 체커 지원 (mypy, pyright)
- 데이터 모양의 명확한 문서화
- 선택적 필드의 명시적 처리
세 가지 출력 모드
도구는 각각 다른 사용 사례에 맞는 세 가지 출력 형식을 지원합니다.
@dataclass (표준 라이브러리, 기본값)
표준 라이브러리, 의존성 없음. 내부 데이터 구조, 설정, 오버헤드를 없애고 싶을 때 최적:
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
API 유효성 검사, 설정 관리, 런타임 유효성 검사와 직렬화가 필요한 곳에 최적. FastAPI 애플리케이션의 표준 선택:
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
Pydantic은 인스턴스화 시 유효성 검사, .model_dump()로 직렬화, .model_validate()로 딕셔너리 파싱을 제공합니다.
TypedDict (Python 3.8+)
런타임 동작을 바꾸지 않고 딕셔너리를 타입 체크하는 데 최적. 플레인 딕셔너리를 기대하는 라이브러리와 함께 사용할 때 유용:
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 타입에서 Python 타입으로 매핑
| JSON | Python |
|---|---|
"string" | str |
42 | int |
3.14 | float |
true / false | bool |
null | Optional[Any] = None |
["a", "b"] | List[str] |
[1, "a", true] 혼합 | List[Union[int, str, bool]] |
{} 중첩 객체 | 별도 클래스 |
중첩 객체 처리
각 중첩 객체는 필드 이름에서 파생된 PascalCase의 독립적인 클래스가 됩니다. 클래스는 항상 의존성 순서로 출력됩니다 — 자식이 부모보다 먼저 — 생성된 코드를 재정렬 없이 바로 사용할 수 있습니다:
입력 JSON:
{
"user": {
"profile": {
"bio": "개발자",
"location": "서울"
},
"name": "김철수",
"age": 30
},
"timestamp": 1713456789
}
생성된 @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
FastAPI + Pydantic 실용 예시
가장 일반적인 사용 사례는 FastAPI 엔드포인트 응답 파싱입니다:
import httpx
from pydantic import BaseModel
from typing import List
class Post(BaseModel):
id: int
title: str
body: str
userId: int
# API 응답을 타입이 있는 모델로 파싱
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) # 완전히 타입이 있음
표준 @dataclass와 dacite
표준 라이브러리 dataclass를 선호하지만 딕셔너리 → dataclass 변환도 원한다면:
from dacite import from_dict
from dataclasses import dataclass
@dataclass
class User:
id: int
name: str
email: str
data = {"id": 1, "name": "김철수", "email": "[email protected]"}
user = from_dict(User, data)
print(user.name) # 김철수
루트 클래스 이름 커스터마이징
기본 최상위 클래스 이름은 Root입니다. 도메인에 맞게 변경하세요:
- API 응답 →
ApiResponse,SearchResult,UserProfile - 설정 파일 →
AppConfig,DatabaseConfig - 웹훅 페이로드 →
WebhookEvent,PaymentNotification
알아야 할 한계
JSON은 스키마가 아닌 샘플입니다. 필드가 실제로 여러 타입일 수 있어도, 도구는 샘플에서 보이는 타입만 볼 수 있습니다. 프로덕션 사용 전에 항상 Optional 필드와 union 타입을 검토하세요.
중첩이 깊으면 많은 클래스가 생성됩니다. 깊게 중첩된 JSON은 같은 깊이의 클래스 계층을 생성합니다. 이것은 올바른 동작이며 버그가 아닙니다.
관련 도구
- JSON to TypeScript → — JSON에서 TypeScript 인터페이스 생성
- JSON to Go Struct → — JSON에서 Go 구조체 생성
- JSON Formatter → — 변환 전에 JSON 정형화 및 검증
JSON을 붙여넣고 출력 형식을 선택하세요. JSON to Python 데이터클래스 생성기 열기 →