JSON to Dart

Buat kelas Dart dari JSON dengan fromJson dan toJson

Coba contoh
Nama root class:

Input JSON

Output Dart

Berjalan lokal ยท Aman untuk menempel rahasia
Kelas Dart akan muncul di siniโ€ฆ

Apa itu Konversi JSON ke Dart?

Konversi JSON ke Dart mengambil objek JSON mentah dan menghasilkan definisi kelas Dart dengan field bertipe, konstruktor bernama, factory fromJson, dan metode toJson. Dart tidak memiliki reflection di Flutter (dart:mirrors dinonaktifkan), sehingga Anda tidak dapat melakukan deserialisasi JSON ke objek bertipe tanpa menulis kode pemetaan secara eksplisit. Setiap respons REST API, dokumen Firebase, atau payload konfigurasi memerlukan kelas model Dart yang sesuai sebelum Anda dapat mengakses field-nya dengan type safety.

Kelas model Dart standar untuk JSON mendeklarasikan field final untuk setiap kunci, konstruktor dengan parameter bernama (menggunakan kata kunci required untuk field non-nullable), factory constructor bernama fromJson yang membaca dari Map String ke dynamic, dan metode toJson yang mengembalikan Map String ke dynamic. Objek JSON bersarang menjadi kelas terpisah. Array menjadi field List bertipe. Nilai JSON nullable menggunakan sintaks null-safety Dart dengan sufiks ? pada tipenya.

Menulis kelas model ini secara manual berarti membaca setiap kunci JSON, menentukan tipe Dart-nya, membuat cast fromJson untuk setiap field (termasuk pemetaan list dengan .map().toList()), membangun map literal toJson, dan mengulangi proses untuk setiap objek bersarang. Untuk objek JSON dengan 12 field dan 2 objek bersarang, itu berarti 3 kelas, 6 baris factory, dan puluhan ekspresi cast. Sebuah konverter menghasilkan semua ini dalam milidetik dari satu kali paste.

Mengapa Menggunakan Konverter JSON ke Dart?

Membuat kelas model Dart dari JSON secara manual melibatkan pembacaan nama field, menebak tipe dari nilai sampel, menulis cast fromJson dengan penanganan null yang benar, dan mengulangi proses untuk objek bersarang. Ketika bentuk API berubah, setiap pembaruan field menyentuh konstruktor, fromJson, dan toJson sekaligus. Sebuah konverter menghilangkan pekerjaan berulang tersebut.

โšก
Pembuatan kelas secara instan
Tempelkan JSON dan dapatkan kelas Dart lengkap dengan konstruktor, factory fromJson, dan metode toJson dalam kurang dari satu detik. Objek bersarang dan list terdeteksi dan dipetakan secara otomatis.
๐Ÿ”’
Pemrosesan yang mengutamakan privasi
Konversi berjalan sepenuhnya di browser Anda menggunakan JavaScript. Data JSON Anda tidak pernah meninggalkan perangkat Anda. Kunci API, token, dan payload produksi tetap bersifat pribadi.
๐Ÿ“
Output null-safe
Kelas yang dihasilkan menggunakan null safety Dart yang ketat. Field JSON nullable mendapatkan sufiks tipe ? dan tidak menggunakan kata kunci required di konstruktor. Field non-null ditandai required.
๐Ÿ“ฆ
Tanpa instalasi atau pendaftaran
Buka halaman dan tempelkan JSON Anda. Tidak perlu Dart SDK, tidak ada dependensi pub, tidak ada akun. Berfungsi di perangkat apa pun dengan browser.

Kasus Penggunaan JSON ke Dart

Pengembangan Aplikasi Flutter
Buat kelas model untuk respons REST API yang digunakan oleh paket http atau dio. Tempelkan JSON yang dikembalikan backend Anda dan dapatkan kelas Dart yang siap digunakan dengan jsonDecode dan rendering widget.
Integrasi Firebase / Firestore
Buat kelas model bertipe untuk snapshot dokumen Firestore. Tempelkan dokumen sampel sebagai JSON, hasilkan kelas Dart, dan gunakan fromJson dengan snapshot.data() di lapisan repository Anda.
Model State Management
Definisikan objek state bertipe untuk Riverpod, Bloc, atau Provider. Tempelkan bentuk state yang diharapkan sebagai JSON dan dapatkan kelas Dart immutable dengan toJson untuk persistensi dan hidrasi state.
Pembuatan Kode API Client
Hasilkan model request dan response untuk API client Retrofit atau Chopper. Tempelkan payload JSON sampel dan dapatkan kelas Dart yang sesuai dengan skema respons OpenAPI Anda.
Pengujian Otomatis
Buat fixture pengujian bertipe dari respons API nyata. Tempelkan sampel JSON, hasilkan kelas model, dan gunakan langsung dalam unit test dan widget test tanpa menulis struct fixture secara manual.
Belajar Pola Dart
Mahasiswa yang belajar Flutter dapat menempelkan struktur JSON apa pun dan melihat cara Dart merepresentasikannya: field final, konstruktor bernama, pola factory fromJson, dan anotasi null-safety dalam praktik.

Pemetaan Tipe JSON ke Dart

Setiap nilai JSON dipetakan ke tipe Dart yang spesifik. Tabel di bawah menunjukkan cara konverter menerjemahkan setiap tipe JSON. Kolom Alternatif menampilkan tipe yang digunakan dalam skenario pemetaan yang kurang umum atau manual.

Tipe JSONContohTipe DartAlternatif
string"hello"StringString
number (integer)42intint
number (float)3.14doubledouble
booleantrueboolbool
nullnulldynamicNull / dynamic
object{"k": "v"}NestedClassMap<String, dynamic>
array of strings["a", "b"]List<String>List<String>
array of objects[{"id": 1}]List<Item>List<Item>
mixed array[1, "a"]List<dynamic>List<dynamic>

Pendekatan Serialisasi JSON di Dart

Dart dan Flutter menawarkan beberapa cara untuk menangani serialisasi JSON. fromJson/toJson manual adalah pendekatan paling sederhana dan tidak memerlukan pembuatan kode. Untuk proyek yang lebih besar, solusi berbasis build_runner seperti json_serializable dan freezed menghasilkan boilerplate pada waktu kompilasi, mengurangi kesalahan dan menjaga model tetap konsisten dengan kontrak JSON.

PendekatanDeskripsiSumber
json_serializableCode-generation-based JSON serialization. Generates .g.dart files at build time via build_runner. Type-safe and compile-time verified.Official (Google)
freezedGenerates immutable data classes with copyWith, fromJson/toJson, equality, and pattern matching support. Built on top of json_serializable.Community (rrousselGit)
built_valueGenerates immutable value types with serialization. Enforces immutability patterns. Used in larger codebases with strict data modeling.Google
dart_mappableAnnotation-based mapper that generates fromJson, toJson, copyWith, and equality. Simpler setup than freezed with similar features.Community
Manual fromJson/toJsonHand-written factory constructors and toJson methods. No code generation needed. Full control over the mapping logic.Built-in Dart

Manual vs json_serializable vs freezed

Dart memiliki tiga pendekatan umum untuk kelas model JSON. fromJson/toJson manual tidak memerlukan dependensi. json_serializable mengotomatiskan kode pemetaan. freezed menambahkan immutabilitas, copyWith, dan pattern matching di atas json_serializable.

Manual fromJson/toJson
Tulis factory fromJson dan metode toJson secara manual. Tanpa dependensi, tanpa langkah build_runner. Anda memiliki kontrol penuh atas logika cast dan penanganan error. Terbaik untuk proyek kecil dengan beberapa model, atau saat Anda memerlukan deserialisasi kustom yang tidak dapat diekspresikan oleh generator kode. Ini adalah format output yang dihasilkan alat ini.
json_serializable
Beri anotasi kelas Anda dengan @JsonSerializable() dan jalankan dart run build_runner build. Generator membuat file .g.dart dengan fungsi _$ClassFromJson dan _$ClassToJson. Mendukung @JsonKey untuk penggantian nama field, nilai default, dan konverter kustom. Pilihan standar untuk proyek Flutter menengah hingga besar.
freezed
Beri anotasi dengan @freezed dan dapatkan kelas immutable dengan fromJson, toJson, copyWith, kesetaraan (== dan hashCode), dan toString yang dihasilkan secara otomatis. Mendukung union type untuk pola sealed class. Memerlukan freezed dan json_serializable sebagai dev dependency. Terbaik untuk model state management dan objek domain yang kompleks.

Contoh Kode

Contoh-contoh ini menunjukkan cara menggunakan kelas Dart yang dihasilkan untuk deserialisasi JSON, cara menyiapkan json_serializable dengan build_runner, dan cara menghasilkan kelas Dart secara programatik dari JavaScript dan Python.

Dart (manual fromJson / toJson)
import 'dart:convert';

class User {
  final int id;
  final String name;
  final String email;
  final bool active;
  final Address address;
  final List<String> tags;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.active,
    required this.address,
    required this.tags,
  });

  factory User.fromJson(Map<String, dynamic> json) => User(
    id: json['id'] as int,
    name: json['name'] as String,
    email: json['email'] as String,
    active: json['active'] as bool,
    address: Address.fromJson(json['address'] as Map<String, dynamic>),
    tags: (json['tags'] as List<dynamic>).map((e) => e as String).toList(),
  );

  Map<String, dynamic> toJson() => {
    'id': id,
    'name': name,
    'email': email,
    'active': active,
    'address': address.toJson(),
    'tags': tags,
  };
}

class Address {
  final String street;
  final String city;
  final String zip;

  Address({required this.street, required this.city, required this.zip});

  factory Address.fromJson(Map<String, dynamic> json) => Address(
    street: json['street'] as String,
    city: json['city'] as String,
    zip: json['zip'] as String,
  );

  Map<String, dynamic> toJson() => {'street': street, 'city': city, 'zip': zip};
}

void main() {
  final jsonStr = '{"id":1,"name":"Alice","email":"alice@example.com","active":true,"address":{"street":"123 Main","city":"Springfield","zip":"12345"},"tags":["admin","user"]}';
  final user = User.fromJson(jsonDecode(jsonStr));
  print(user.name); // -> Alice
  print(jsonEncode(user.toJson())); // -> round-trip back to JSON
}
Dart (json_serializable + build_runner)
// pubspec.yaml dependencies:
//   json_annotation: ^4.8.0
//   dev_dependencies:
//     build_runner: ^2.4.0
//     json_serializable: ^6.7.0

import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart'; // generated by: dart run build_runner build

@JsonSerializable()
class User {
  final int id;
  final String name;
  final String email;
  @JsonKey(name: 'is_active')
  final bool isActive;
  final List<String> tags;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.isActive,
    required this.tags,
  });

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

// Run code generation:
// dart run build_runner build --delete-conflicting-outputs
JavaScript (generate Dart classes from JSON)
function jsonToDart(obj, name = "Root") {
  const classes = [];
  function infer(val, fieldName) {
    if (val === null) return "dynamic";
    if (typeof val === "string") return "String";
    if (typeof val === "number") return Number.isInteger(val) ? "int" : "double";
    if (typeof val === "boolean") return "bool";
    if (Array.isArray(val)) {
      const first = val.find(v => v !== null);
      if (!first) return "List<dynamic>";
      return `List<${infer(first, fieldName)}>`;
    }
    if (typeof val === "object") {
      const cls = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
      build(val, cls);
      return cls;
    }
    return "dynamic";
  }
  function build(obj, cls) {
    const fields = Object.entries(obj).map(([k, v]) =>
      `  final ${infer(v, k)} ${k};`
    );
    classes.push(`class ${cls} {\n${fields.join("\n")}\n}`);
  }
  build(obj, name);
  return classes.join("\n\n");
}

console.log(jsonToDart({ id: 1, name: "Alice", scores: [98, 85] }, "User"));
// class User {
//   final int id;
//   final String name;
//   final List<int> scores;
// }
Python (generate Dart model from JSON)
import json

def json_to_dart(obj: dict, class_name: str = "Root") -> str:
    classes = []

    def infer(val, name):
        if val is None:
            return "dynamic"
        if isinstance(val, bool):
            return "bool"
        if isinstance(val, int):
            return "int"
        if isinstance(val, float):
            return "double"
        if isinstance(val, str):
            return "String"
        if isinstance(val, list):
            if not val:
                return "List<dynamic>"
            return f"List<{infer(val[0], name)}>"
        if isinstance(val, dict):
            cls = name[0].upper() + name[1:]
            build(val, cls)
            return cls
        return "dynamic"

    def build(obj, cls):
        fields = [f"  final {infer(v, k)} {k};" for k, v in obj.items()]
        classes.append(f"class {cls} {{\n" + "\n".join(fields) + "\n}")

    build(obj, class_name)
    return "\n\n".join(classes)

data = json.loads('{"id": 1, "name": "Alice", "active": true}')
print(json_to_dart(data, "User"))
# class User {
#   final int id;
#   final String name;
#   final bool active;
# }

Pertanyaan yang Sering Diajukan

Mengapa Flutter tidak bisa menggunakan dart:mirrors untuk deserialisasi JSON?
Flutter menonaktifkan dart:mirrors (library reflection) karena tree-shaking mengharuskan kompiler mengetahui kode mana yang digunakan pada waktu kompilasi. Reflection akan mencegah kompiler menghapus kelas yang tidak digunakan, sehingga meningkatkan ukuran aplikasi. Itulah mengapa proyek Flutter memerlukan metode fromJson/toJson yang eksplisit atau pembuatan kode, bukan reflection saat runtime.
Haruskah saya menggunakan json_serializable atau menulis fromJson secara manual?
Untuk proyek dengan kurang dari 10 kelas model, fromJson/toJson yang ditulis manual sudah cukup dan tidak menambah dependensi build. Setelah Anda memiliki lebih dari 10 model, atau model yang sering berubah, json_serializable menghemat waktu dan mengurangi kesalahan copy-paste. Alat ini menghasilkan kode pemetaan dari anotasi, sehingga penambahan field hanya memerlukan menjalankan ulang build_runner.
Bagaimana konverter menangani objek JSON bersarang?
Setiap objek JSON bersarang menjadi kelas Dart terpisah. Jika field JSON bernama "address" berisi objek dengan kunci "street" dan "city", konverter membuat kelas Address dengan field-field tersebut dan menentukan tipe field induk sebagai Address. Factory fromJson melakukan cast pada map bersarang dan meneruskannya ke Address.fromJson.
Apa yang terjadi ketika field JSON bernilai null?
Field null diberi tipe dynamic dengan sufiks ? karena konverter tidak dapat menentukan tipe yang dimaksud hanya dari nilai null. Ganti dynamic? dengan tipe yang benar (String?, int?, dll.) setelah Anda mengetahuinya dari kontrak API. Null safety Dart kemudian akan memaksakan pemeriksaan null yang benar pada waktu kompilasi.
Bagaimana cara menangani kunci JSON yang bukan identifier Dart yang valid?
Kunci JSON seperti "first-name" atau "2nd_place" bukan nama field Dart yang valid. Dengan fromJson manual, Anda dapat memetakan kunci JSON apa pun ke nama field Dart mana pun di factory constructor. Dengan json_serializable, gunakan @JsonKey(name: 'first-name') untuk memberi anotasi pada field. Konverter secara otomatis mengonversi nama kunci ke field Dart camelCase.
Bisakah saya menggunakan freezed dengan output dari alat ini?
Alat ini menghasilkan kelas Dart standar dengan fromJson/toJson manual. Untuk mengonversi ke freezed, ubah kelas agar menggunakan anotasi @freezed, hapus konstruktor dan factory yang ditulis manual, dan tambahkan mixin freezed. Kemudian jalankan build_runner untuk menghasilkan file .freezed.dart dan .g.dart. Nama field dan tipe dari output yang dihasilkan dapat digunakan langsung.
Apa perbedaan antara raw map dan kelas Dart bertipe untuk JSON?
Raw map (Map String ke dynamic) memberi Anda akses langsung ke data JSON tanpa pengecekan tipe. Anda harus melakukan cast setiap nilai di titik pemanggilan, dan kesalahan ketik pada nama kunci gagal secara diam-diam saat runtime. Kelas Dart bertipe menangkap ketidakcocokan tipe di batas fromJson, menyediakan autocompletion IDE untuk nama field, dan membuat refactoring menjadi aman. Perbedaan performa dapat diabaikan; manfaatnya sepenuhnya tentang ketepatan dan kemudahan pemeliharaan.