JSON dengan dart:convert
Encode/decode JSON: dari API ke objek dan sebaliknya.
Bahasa universal data
Hampir semua API berbicara JSON: format teks ringan untuk pertukaran data. Di Dart, JSON dipetakan ke Map<String, dynamic> dan List<dynamic>, dan library dart:convert adalah penerjemahnya.
Analogi: JSON itu seperti bahasa Inggris di bandara internasional. Sistem berbeda (server Python, aplikasi Dart) berkomunikasi lewat "bahasa" yang sama-sama dipahami.
Kenapa JSON penting?
Karena tanpa JSON skill, aplikasimu terisolasi: tidak bisa ambil data API, tidak bisa simpan konfigurasi, tidak bisa bicara dengan backend. JSON adalah gerbang integrasi.
Decode: JSON string → Dart
import 'dart:convert';
void main() {
String jsonStr = '''
{
"nama": "Budi",
"umur": 17,
"hobi": ["membaca", "ngoding"],
"aktif": true
}
''';
// jsonDecode: string -> Map<String, dynamic>
var data = jsonDecode(jsonStr);
print(data['nama']); // Budi
print(data['hobi'][0]); // membaca
print(data['umur'].runtimeType); // int (otomatis!)
// Aman dengan cast eksplisit
Map<String, dynamic> user = jsonDecode(jsonStr);
String nama = user['nama'] as String;
print('Halo, $nama');
}jsonDecode mengubah string menjadi Map/List Dart. Tipe angka otomatis (int vs double), boolean, null, dan string nested.
Contoh kedua, JSON array:
import 'dart:convert';
void main() {
String jsonArr = '[{"nama":"Budi"},{"nama":"Ani"}]';
List<dynamic> list = jsonDecode(jsonArr);
for (var item in list) {
print(item['nama']);
}
// Ke List<String> rapi
var nama = list.map((e) => (e as Map)['nama'] as String).toList();
print(nama); // [Budi, Ani]
}Encode: Dart → JSON string
import 'dart:convert';
void main() {
var user = {
'nama': 'Budi',
'umur': 17,
'hobi': ['membaca', 'ngoding'],
};
String json = jsonEncode(user);
print(json); // {"nama":"Budi","umur":17,"hobi":["membaca","ngoding"]}
// Pretty print untuk debugging
var pretty = JsonEncoder.withIndent(' ').convert(user);
print(pretty);
}jsonEncode hanya menerima tipe yang bisa di-JSON-kan: Map, List, String, num, bool, null. Objek custom? Harus diubah ke Map dulu (lihat pola fromJson/toJson).
Pola fromJson/toJson pada class
import 'dart:convert';
class Pengguna {
String nama;
int umur;
Pengguna(this.nama, this.umur);
// JSON -> objek
factory Pengguna.dariJson(Map<String, dynamic> json) {
return Pengguna(
json['nama'] as String,
json['umur'] as int,
);
}
// objek -> JSON
Map<String, dynamic> keJson() => {
'nama': nama,
'umur': umur,
};
}
void main() {
// Simulasi data dari API
String responApi = '{"nama":"Ani","umur":20}';
var user = Pengguna.dariJson(jsonDecode(responApi));
print('Halo ${user.nama}, umur ${user.umur}');
// Kirim kembali ke server
String untukServer = jsonEncode(user.keJson());
print(untukServer);
}Pola dariJson/keJson adalah standar industri Flutter. Setiap model data memilikinya. (Package json_serializable bisa menggenerasinya otomatis untuk proyek besar.)
Kesalahan umum
1. Cast tanpa as
void main() {
var data = jsonDecode('{"umur": 17}');
// String s = data['umur']; // ERROR: dynamic -> String
int umur = data['umur'] as int; // BENAR
print(umur);
}Nilai dari JSON bertipe dynamic. Selalu cast (as) atau validasi sebelum dipakai sebagai tipe spesifik.
2. Kunci tidak ada → null
void main() {
var data = jsonDecode('{"nama": "Budi"}');
// int umur = data['umur'] as int; // ERROR: null!
int umur = (data['umur'] as int?) ?? 0; // BENAR
print(umur);
}API bisa berubah; kunci bisa hilang. Pakai cast nullable + ?? default.
3. jsonEncode objek custom langsung
class A {
String x = 'hi';
}
void main() {
// print(jsonEncode(A())); // ERROR: tidak bisa di-encode!
print(jsonEncode({'x': A().x})); // BENAR: ubah ke Map dulu
}Kesimpulan
jsonDecode (string → Map/List), jsonEncode (Map/List → string), pola dariJson/keJson di class model. Selalu cast eksplisit dan tangani kunci yang mungkin hilang. Kuasai ini dan kamu siap bicara dengan API mana pun.
Catatan teknis:
dart:convertjuga berisiutf8,base64, danLineSplitter. Untuk JSON besar, adaJsonDecoderstreaming. Untuk model kompleks, pertimbangkan code generation viajson_serializable.
Tantangan
Parser daftar pengguna
Diberi JSON string array pengguna (nama, umur). Decode, ubah jadi List<Pengguna> via Pengguna.dariJson, cetak nama yang umurnya >= 18, lalu encode kembali yang lolos ke JSON.
import 'dart:convert';
class Pengguna {
String nama;
int umur;
Pengguna(this.nama, this.umur);
factory Pengguna.dariJson(Map<String, dynamic> j) =>
Pengguna(j['nama'] as String, j['umur'] as int);
Map<String, dynamic> keJson() => {'nama': nama, 'umur': umur};
}
void main() {
String jsonStr = '[{"nama":"Budi","umur":17},{"nama":"Ani","umur":20}]';
// TODO: decode -> List<Pengguna> -> filter >= 18 -> encode
}