Skip to content
Kembali ke Blog
Tutorial

JSON ke Python: dataclass, Pydantic & TypedDict (Panduan 2026)

Ubah JSON menjadi kelas Python dengan benar: dataclass, Pydantic v2, atau TypedDict, tipe Optional, alias camelCase, plus jebakan yang harus dihindari. Gratis.

12 menit membaca

JSON ke Python: dataclass, Pydantic & TypedDict (Panduan 2026)

Tempelkan JSON Anda ke konverter JSON ke Python lalu salin kelas yang dihasilkannya. Itulah jalur tercepat untuk mengubah JSON menjadi Python: tidak ada yang perlu dipasang, tidak ada yang diunggah, semuanya berjalan di browser Anda. Untuk model sekali pakai atau sekadar mengintip respons API yang belum Anda kenal, prosesnya selesai dalam hitungan detik.

Masalah yang lebih sulit justru tidak bisa dipecahkan konverter untuk Anda. Ia menyimpulkan tipe yang benar, tetapi tidak bisa mengambil keputusan yang paling menentukan: mana dari tiga keluaran yang sebenarnya Anda inginkan. Sebuah dataclass, BaseModel milik Pydantic v2, dan TypedDict bisa menggambarkan JSON yang persis sama, tetapi ketiganya berbeda dalam kekuatan keamanan tipe (type-safety), perilaku saat runtime, dan cara Anda memuat data ke dalamnya. Salah pilih, dan Anda entah menanggung dependensi Pydantic tanpa alasan, atau mengira sebuah dataclass memvalidasi input Anda padahal sebenarnya tidak.

Panduan ini membahas matriks keputusan untuk ketiganya, cara konverter menyimpulkan tipe, penanganan camelCase di tiap mode, cara mem-parsing JSON dengan kelas yang Anda hasilkan (termasuk jebakan bersarang yang kerap menjerat banyak orang), Pydantic v2 versus v1, serta kasus-kasus tepi yang perlu Anda ketahui sebelum memercayai hasilnya.

Cara mengubah JSON menjadi Python

Mengubah JSON menjadi Python hanya butuh tiga langkah:

  1. Tempelkan JSON Anda. Masukkan objek, array, atau respons API mentah ke kotak input. Konversi berjalan seketika dan sepenuhnya di sisi klien (client-side).
  2. Pilih dataclass, Pydantic, atau TypedDict. Gunakan sakelar Output untuk berganti gaya keluaran, lalu ubah nama Root bawaan menjadi sesuatu yang bermakna seperti User atau ApiResponse.
  3. Salin atau unduh. Ambil kode Python yang dihasilkan dengan satu klik dan letakkan models.py langsung ke dalam proyek Anda.

Itulah keseluruhan jalur praktisnya. Jika input Anda terminifikasi atau Anda belum yakin ia valid, jalankan dulu lewat JSON formatter supaya konverter membaca JSON yang bersih dan berbentuk rapi. Sisa panduan ini menjelaskan keluarannya agar Anda bisa memperbaiki kasus-kasus yang tidak bisa disimpulkan sendiri oleh sebuah alat.

Bagaimana tipe JSON dipetakan ke Python

Setiap nilai JSON punya padanannya di Python, dan pemetaannya lugas:

Nilai JSONTipe Python
"text"str
42int (presisi arbitrer, tanpa overflow)
3.14, 2e3float
true / falsebool
nullOptional[T] / Optional[Any]
[1, 2, 3]List[T]
{ ... }kelas bernama

Ambil contoh payload REST yang umum:

{ "id": 101, "name": "Ada Lovelace", "email": "ada@example.com", "active": true, "roles": ["admin", "user"] }

Dalam mode dataclass, konverter menghasilkan kelas yang siap pakai:

from dataclasses import dataclass
from typing import List


@dataclass
class Root:
    id: int
    name: str
    email: str
    active: bool
    roles: List[str]

Ada satu nuansa yang membedakan Python. Tipe int-nya berpresisi arbitrer, jadi sebuah snowflake Discord atau ID apa pun yang melampaui 2^53 tetap berupa int biasa tanpa kehilangan presisi. JavaScript akan kehilangan presisi pada nilai yang sama, dan Rust memaksa Anda memilih antara i64, u64, dan f64. Hanya token yang ditulis dengan titik desimal atau eksponen yang disimpulkan sebagai float. Sebuah field yang nilainya selalu null tidak bisa ditentukan tipenya hanya dari sampel, sehingga jatuh kembali menjadi Optional[Any]; tempelkan payload representatif dengan nilai yang terisi untuk mendapatkan tipe yang lebih tajam daripada Any.

dataclass vs Pydantic v2 vs TypedDict — mana yang sebaiknya Anda pakai?

Inilah pilihan yang dikembalikan konverter ke tangan Anda. Versi singkatnya: pilih dataclass ketika Anda ingin penampung data internal tanpa dependensi, Pydantic v2 ketika Anda mem-parsing atau memvalidasi input yang tidak tepercaya, dan TypedDict ketika Anda hanya butuh petunjuk tipe statis di atas dict yang sudah Anda miliki.

DimensidataclassPydantic v2TypedDict
DependensiPustaka standarpip install pydanticPustaka standar (typing)
Validasi runtimeTidakYa — memvalidasi dan meng-coerceTidak — hanya petunjuk
Biaya runtimeRingan (objek nyata)Ada (validasi)Nol (ia sebuah dict)
Parsing bersarang otomatisTidak, manualYa, model_validate rekursifTidak, ia sebuah dict
Alias camelCaseMempertahankan key asliField(alias=...)Sintaks fungsional
Paling cocok untukStruktur internalRespons API, webhook, konfigurasiMemberi tipe pada kode dict lama

Ketiga target terlihat nyaris identik untuk bentuk kecil seperti {"id": 101, "name": "Ada Lovelace", "active": true}. Sebuah dataclass hasil konversi JSON ke Python memberi Anda objek dari pustaka standar:

from dataclasses import dataclass


@dataclass
class Root:
    id: int
    name: str
    active: bool

Versi Pydantic-nya menukar dengan BaseModel, yang tampak serupa tetapi terbukti berguna saat runtime:

from pydantic import BaseModel


class Root(BaseModel):
    id: int
    name: str
    active: bool

Dan sebuah TypedDict Python dari JSON menggambarkan bentuk dict biasa tanpa mengalokasikan apa pun yang baru:

from typing import TypedDict


class Root(TypedDict):
    id: int
    name: str
    active: bool

Field yang sama, tiga kontrak yang sangat berbeda. Karena alat memberi ketiganya sekaligus dari satu sampel, Anda bisa berpindah-pindah di antaranya di dalam alat dan mencocokkan mode dengan kebutuhan: Pydantic ketika Anda mem-parsing data yang tidak Anda kendalikan, dataclass ketika datanya bersifat internal, dan TypedDict ketika Anda hanya ingin mypy memahami dict yang sudah Anda oper ke sana-sini.

Bagaimana konverter menyimpulkan kelas

Tiga aturan mencakup nyaris segala hal yang Anda berikan padanya: satu kelas per bentuk objek, penggabungan key demi key untuk array, dan penanganan cermat atas nilai yang hilang.

Inferensi struktural: satu kelas bernama per objek

Setiap bentuk objek yang berbeda menjadi kelas bernama tersendiri. Objek bersarang tidak disisipkan inline; ia diangkat menjadi definisi terpisah yang dirujuk:

{ "repo": "pydantic", "owner": { "login": "samuelcolvin", "id": 100 } }
from dataclasses import dataclass


@dataclass
class Owner:
    login: str
    id: int


@dataclass
class Root:
    repo: str
    owner: Owner

Objek owner yang bersarang menjadi kelas Owner tersendiri, dirujuk lewat field. Perhatikan urutannya: kelas anak dipancarkan sebelum induk yang memakainya, sehingga modul berjalan tanpa from __future__ import annotations. Bentuk yang identik juga di-deduplikasi, jadi dua field dengan struktur yang sama berbagi satu kelas alih-alih menghasilkan salinan.

Penggabungan array dan field Optional

Ketika Anda mengoper array berisi objek, konverter menggabungkannya key demi key menjadi satu tipe elemen. Sebuah key yang ada di sebagian elemen tetapi hilang dari yang lain menjadi Optional:

{ "users": [{ "id": 1, "nick": "x" }, { "id": 2 }] }
from typing import List, Optional, TypedDict


class User(TypedDict):
    id: int
    nick: Optional[str]


class Root(TypedDict):
    users: List[User]

id muncul di setiap elemen, jadi ia tetap wajib. nick tidak ada pada user kedua, sehingga menjadi Optional[str]. Inilah persisnya alasan satu objek tunggal merupakan sampel yang lemah: alat hanya bisa menandai sebuah field sebagai Optional ketika ia benar-benar melihat key itu hilang di suatu tempat. Berikan array yang representatif dan inferensinya akan mencerminkan bentuk yang sebenarnya.

Optional, None, dan array kosong

Beberapa nilai tidak membawa tipe apa pun dengan sendirinya, dan konverter jujur soal ini. Key yang hilang dari sebagian item array menjadi Optional[T]. Field yang nilainya selalu null menjadi Optional[Any], karena null JSON saja tidak memberi tahu apa pun tentang tipe yang dimaksud. Array kosong atau array dengan tipe elemen campuran jatuh kembali menjadi List[Any]. Tak satu pun dari ini adalah bug; itu adalah cara alat menolak menebak-nebak. Ganti setiap Any dengan tipe konkret begitu Anda punya sampel yang menunjukkannya, dan ingat bahwa int berpresisi arbitrer milik Python berarti ID besar tidak pernah memaksa Anda ke tipe numerik yang lebih lebar seperti yang terjadi di Rust atau JavaScript.

Menangani key camelCase di tiap mode

Key JSON sering kali camelCase sementara field Python yang idiomatis adalah snake_case. Tidak ada satu jawaban yang benar di sini, jadi tiap mode menyelesaikannya secara berbeda, dan perbedaan itu layak Anda pahami sebelum menyalin keluarannya.

dataclass. Sebuah dataclass tidak punya mekanisme alias bawaan. Agar Root(**data) tetap berfungsi, konverter mempertahankan key asli sebagai nama field selama ia merupakan identifier Python yang valid, jadi publicRepos tetap publicRepos. Memaksanya menjadi snake_case akan merusak **data dengan TypeError.

Pydantic v2. Di sini Anda mendapat hasil yang idiomatis. Field diubah namanya menjadi snake_case dengan Field(alias=...) yang memetakan kembali ke key JSON yang persis, ditambah model_config = ConfigDict(populate_by_name=True) sehingga Anda bisa membangun model lewat nama field maupun lewat alias:

from pydantic import BaseModel, ConfigDict, Field


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

    login: str
    public_repos: int = Field(alias="publicRepos")
    created_at: str = Field(alias="createdAt")

Itulah yang membuat Root.model_validate(api_json) bisa melakukan round-trip payload camelCase yang sesungguhnya sementara kode Anda tetap enak dibaca.

TypedDict. Key yang berupa identifier biasa dipakai langsung. Begitu muncul key yang bukan identifier, konverter beralih ke sintaks fungsional TypedDict('User', {...}) untuk mempertahankan key yang persis, yang dibahas di bagian berikutnya.

Kata kunci Python dan key non-identifier

Key JSON hanyalah string, jadi tidak ada yang mencegah sebuah API mengirim class, from, atau first-name. Masing-masing akan menjadi syntax error jika dipakai sebagai atribut Python mentah, sehingga konverter membersihkannya.

Key yang merupakan kata kunci Python diberi garis bawah di akhir: class menjadi class_, from menjadi from_. Dalam mode Pydantic, ia juga mempertahankan Field(alias=...) supaya model tetap membaca key asli dari jaringan:

from pydantic import BaseModel, ConfigDict, Field


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

    class_: str = Field(alias="class")
    from_: str = Field(alias="from")

Key dengan tanda hubung, spasi, atau diawali angka dibersihkan menjadi identifier yang valid dalam mode dataclass dan Pydantic. TypedDict adalah satu-satunya mode yang bisa mempertahankan key literal, memakai bentuk fungsional sehingga "first-name" bertahan tanpa diubah:

from typing import TypedDict

Root = TypedDict("Root", {"first-name": str, "2fa": bool})

Hasilnya selalu bisa dijalankan, dan dalam mode TypedDict key tetap sama persis byte demi byte dengan yang dikirim API.

Mem-parsing JSON dengan kelas yang dihasilkan

Menghasilkan kelas baru separuh pekerjaan. Memuat JSON ke dalamnya adalah tempat ketiga mode ini berbeda tajam, dan tempat satu asumsi populer ternyata keliru.

dataclass. Untuk objek datar, json.loads plus Root(**data) langsung berfungsi:

import json
from dataclasses import dataclass
from typing import List


@dataclass
class Root:
    id: int
    name: str
    roles: List[str]


data = json.loads('{"id": 101, "name": "Ada Lovelace", "roles": ["admin"]}')
root = Root(**data)
print(root.name, root.roles)

Tetapi dataclass tidak melakukan rekursi. Jika JSON punya objek bersarang, Root(**data) mengisi level teratas dan membiarkan setiap anak sebagai dict biasa, bukan kelas Owner yang Anda hasilkan. Untuk mem-parsing seluruh pohon, bangun sendiri anak-anaknya, gunakan pustaka seperti dacite atau pydantic.dataclasses, atau alihkan alat ke mode Pydantic. Inilah jebakan yang tidak pernah disebut oleh kebanyakan konverter.

Pydantic v2. Satu panggilan mem-parsing dan memvalidasi seluruh pohon:

import json
from pydantic import BaseModel


class Root(BaseModel):
    id: int
    name: str


root = Root.model_validate(json.loads('{"id": 101, "name": "Ada Lovelace"}'))
print(root.name)

Ketidakcocokan tipe memunculkan ValidationError yang jelas alih-alih lolos diam-diam. Itulah imbalan atas dependensinya: model tersebut adalah validator runtime, jadi panggilan model_validate yang berhasil kembali merupakan jaminan bahwa data cocok, bukan sekadar keyakinan pemeriksa tipe bahwa data itu cocok.

TypedDict. Saat runtime, TypedDict adalah dict biasa. Menganotasi data: Root = json.loads(text) semata untuk pemeriksa statis; tidak ada yang divalidasi ketika kode berjalan. Jika Anda butuh penegakan yang sesungguhnya, jalankan mypy di CI atau beralih ke Pydantic. Memilih mode berarti memilih seberapa banyak jaminan runtime yang Anda inginkan, dan ketika sebuah kontrak perlu melampaui tipe, panduan validasi JSON Schema membahas cara menegakkan struktur dari ujung ke ujung.

Pydantic v2 vs v1 — apa yang berubah

Konverter memancarkan sintaks v2. Banyak basis kode masih berjalan di v1, dan menempelkan keluaran v2 ke proyek v1 akan gagal karena metode yang berganti nama, bukan karena logikanya. Berikut pemetaannya:

TugasPydantic v2 (keluaran alat)Pydantic v1
Mem-parsing dictmodel_validate(data)parse_obj(data)
Mem-parsing JSON mentahmodel_validate_json(text)parse_raw(text)
Mengonfigurasi modelmodel_config = ConfigDict(...)class Config internal
Serialisasi ke dictmodel_dump()dict()
Serialisasi ke JSONmodel_dump_json()json()

Perilaku alias juga diperketat: di v2 Anda perlu populate_by_name=True bersama Field(alias=...) untuk membangun model lewat nama field maupun lewat alias, itulah sebabnya alat menyertakannya. Aturan praktisnya singkat. Naikkan ke v2 jika bisa, karena ia lebih cepat dan menjadi sasaran pengembangan saat ini; kalau tidak, tulis ulang model_validate kembali menjadi parse_obj dan ConfigDict kembali menjadi Config internal.

json-to-python vs quicktype vs datamodel-code-generator vs manual

Tidak ada satu cara terbaik untuk menghasilkan kelas Python dari JSON. Semuanya bergantung pada di mana JSON itu berada dan dari apa Anda memulai.

PendekatanPaling cocok untukCatatan
Konverter online (alat ini, jsonlint, codeshack)Konversi sekali pakai, payload sensitif, tanpa instalasiMenyimpulkan dari sampel, sepenuhnya di sisi klien
quicktypeKeluaran multi-bahasa, codegen dalam pipelineJuga berbasis sampel; dukungan Python-nya lebih tipis soal alias dan pilihan mode
datamodel-code-generatorMenghasilkan Pydantic dari JSON Schema atau OpenAPIInputnya sebuah schema, bukan sampel — lebih otoritatif ketika Anda memilikinya
Menulis kelas dengan tanganPayload kecil, belajar sintaksKendali penuh, tetapi merepotkan dan mudah menyimpang

Perbedaan yang layak Anda serap: konverter online dan quicktype sama-sama menyimpulkan tipe dari sampel JSON, sementara datamodel-code-generator membaca spesifikasi JSON Schema atau OpenAPI sebagai sumber kebenarannya. Pakai alat berbasis sampel untuk eksplorasi dan pekerjaan sekali pakai; andalkan yang berbasis schema ketika sebuah kontrak sudah ada. Jika basis kode Anda TypeScript alih-alih Python, pendekatan berbasis sampel yang sama berlaku dengan konverter JSON ke TypeScript, dan panduan interface JSON ke TypeScript mengupas sisi itu secara mendalam. Untuk sudut pandang validasi runtime dalam bahasa terkompilasi yang bertipe kuat, panduan struct JSON ke Rust memberi perbandingan yang berguna: serde adalah Pydantic-nya Rust.

Jebakan umum saat menghasilkan Python dari JSON

Kelas yang dihasilkan hanyalah titik awal. Waspadai hal-hal ini sebelum Anda mengandalkan keluarannya dengan data langsung.

  • Satu sampel jarang mengungkap setiap bentuk. Optional hanya bisa disimpulkan dari elemen array yang benar-benar berbeda. Tempelkan array yang representatif agar sifat opsionalnya akurat, bukan tebakan dari satu objek yang kebetulan.
  • Dataclass tidak memvalidasi. Root(**data) hanya menugaskan field; ia tidak memeriksa tipe apa pun dan tidak melakukan rekursi ke mana pun. Jika Anda butuh penegakan, gunakan Pydantic.
  • JSON bersarang merusak Root(**data). Hanya level teratas yang terisi; anak-anaknya tetap dict. Beralih ke model_validate milik Pydantic, atau gunakan dacite.
  • Field yang selalu null menjadi Optional[Any]. Perlakukan sebagai placeholder, bukan opsional biasa, dan beri ia tipe yang sebenarnya begitu Anda mengetahuinya.
  • Keluaran v2 di proyek v1. model_validate akan tidak terdefinisi. Naikkan ke v2 atau tulis ulang menjadi parse_obj.
  • Tanggal yang dibiarkan sebagai str tidak bisa dipakai untuk hitungan tanggal. Ubah field menjadi datetime, atau di Pydantic gunakan field datetime supaya ia mem-parsing ISO 8601 untuk Anda.

Pertanyaan yang sering diajukan

Sebaiknya saya pakai dataclass, Pydantic, atau TypedDict untuk JSON?

Pakai dataclass untuk penampung data internal tanpa dependensi. Pakai Pydantic v2 ketika Anda mem-parsing atau memvalidasi input yang tidak tepercaya, karena ia menegakkan tipe saat runtime. Pakai TypedDict untuk menambahkan petunjuk statis pada dict yang sudah Anda miliki, tanpa biaya runtime. Ketika data datang dari luar kendali Anda, jadikan Pydantic pilihan bawaan.

Apakah Pydantic memvalidasi JSON saat runtime?

Ya. Root.model_validate(data) memvalidasi dan meng-coerce tipe seiring kode berjalan, memunculkan ValidationError jika inputnya buruk. Dataclass tidak melakukan keduanya — Root(**data) hanya menugaskan field. TypedDict pun tidak melakukan keduanya; ia sekadar petunjuk untuk pemeriksa statis seperti mypy dan berperilaku sebagai dict biasa saat runtime.

Bagaimana cara memberi tipe pada field yang kadang tidak disertakan JSON?

Beri tipe Optional[T]. Ketika sebuah key hanya muncul di sebagian elemen array, konverter menandainya Optional secara otomatis. Di Pydantic, beri field itu nilai default seperti = None supaya key yang hilang tidak memicu error validasi. Field dataclass bisa diberi default dengan cara yang sama lewat field(default=None).

Mengapa dataclass saya gagal mem-parsing JSON bersarang?

Karena Root(**data) tidak melakukan rekursi. Ia mengisi field level teratas dan membiarkan objek bersarang sebagai dict biasa alih-alih kelas anak yang Anda hasilkan. Untuk mem-parsing seluruh pohon dalam satu panggilan, beralih ke model_validate milik Pydantic, atau tambahkan rekursi dengan dacite atau pydantic.dataclasses.

Menjadi tipe Python apa sebuah integer JSON yang besar?

int. Integer Python berpresisi arbitrer, jadi sebuah snowflake atau ID Discord yang melampaui 2^53 tetap berupa int biasa tanpa kehilangan presisi. Anda tidak pernah mengalami penurunan presisi seperti pada JavaScript, dan tidak pernah harus memilih antara i64 dan u64 seperti yang dipaksakan Rust.

Bagaimana key JSON camelCase ditangani di tiap mode?

Dataclass mempertahankan key asli sehingga Root(**data) tetap berfungsi. Pydantic mengubah nama field menjadi snake_case dengan Field(alias="camelKey") plus populate_by_name=True, sehingga bisa round-trip data API yang sesungguhnya. TypedDict memakai sintaks fungsional TypedDict('Name', {...}) untuk mempertahankan key apa pun yang bukan identifier valid.

Bagaimana cara menangani key JSON yang merupakan kata kunci Python seperti class?

Konverter menambahkan garis bawah di akhir, mengubah class menjadi class_ supaya kode tetap valid. Dalam mode Pydantic, ia juga menambahkan Field(alias="class") yang memetakan field kembali ke key asli dari jaringan, sehingga namanya sah dan model tetap membaca payload yang sesungguhnya.

Apakah JSON saya tetap privat saat memakai konverter JSON ke Python online?

Ya. Konversi berjalan 100% di browser Anda dengan JavaScript. JSON Anda — termasuk token, ID, dan data pelanggan — tidak pernah meninggalkan halaman dan tidak pernah dikirim ke server. Ia bahkan bekerja secara offline begitu halaman selesai dimuat. Ketika Anda siap, coba konverter JSON ke Python pada payload Anda sendiri.

Tag: python json pydantic type-safety developer-tools

Artikel Terkait

Lihat semua artikel