Flutter JSON Serializable Generator

Generator for converting to and from JSON

Yudi Setiawan
Nusanet Developers
7 min readMay 23, 2019

--

Pengenalan

Di artikel sebelumnya saya sudah pernah membahas tentang bagaimana cara melakukan parsing JSON.

Pada artikel tersebut kita belajar tentang bagaimana memahami dasar-dasar untuk melakukan proses parsing JSON secara manual. Lalu, di artikel kali ini kita akan belajar tentang pemakaian parsing JSON secara otomatis menggunakan package yang bernama json_serializable.

Contoh Penggunaan

Untuk contohnya kita akan membuat proses parsing JSON yang paling mudah untuk dipahami yaitu sebagai berikut.

  1. JSON Object
  2. JSON Object didalam JSON Object
  3. JSON Array
  4. JSON dengan data kompleks

Persiapan

Pada contoh kali ini kita akan menggunakan respon JSON dari endpoint. Jadi, pertama-tama kita persiapkan terlebih dahulu package yang kita perlukan dan tambahkan di file pubspec.yaml.

name: json_serializable_sample
description: A new flutter project about how to use json serializable
version: 1.0.0+1

environment:
sdk: ">=2.1.0 <3.0.0"

dependencies
:
flutter:
sdk: flutter

# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2

# Automatically generate code for converting to and from JSON by annotating Dart classes.
json_serializable: ^3.0.0

# Future-based API for making HTTP requests.
http: ^0.12.0+2

# Tools to write binaries that run builders.
build_runner: ^1.4.0

dev_dependencies:
flutter_test:
sdk: flutter

flutter:

# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true

Sekarang kita persiapkan kode untuk UI-nya di file main.dart seperti berikut.

import 'package:flutter/material.dart';

import 'api_service.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
theme:
ThemeData(primaryColor: Colors.blue, accentColor: Colors.tealAccent),
title: "JSON Serializable Generator",
);
}
}

class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
var result = "Result in here";

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"JSON Serializable Generator",
style: TextStyle(color: Colors.white),
),
),
body: SafeArea(
child: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
// TODO: do something in here
},
child: Text("JSON Object"),
),
RaisedButton(
onPressed: () {
// TODO: do something in here
},
child: Text("JSON Object didalam JSON Object"),
),
RaisedButton(
onPressed: () {
// TODO: do something in here
},
child: Text("JSON Array"),
),
RaisedButton(
onPressed: () {
// TODO: do something in here
},
child: Text("JSON dengan data kompleks"),
),
Expanded(
child: Center(
child: Text(
result,
textAlign: TextAlign.center,
),
),
)
],
),
),
),
);
}
}

Output dari kode tersebut adalah seperti berikut.

Tampilan utama

Sekarang kita buat file baru bernama api_service.dart dan berikut isi dari file tersebut.

import 'dart:convert';

import 'package:http/http.dart' as http;

class ApiService {
final client = http.Client();
final baseUrl = "http://api.bengkelrobot.net:8001";

// TODO: do something in here

}

Contoh JSON Object

Sekarang kita coba untuk melakukan parsing json menggunakan json_serializable. Caranya, kita buat file baru bernama sample1.dart dan isi dengan kode berikut.

import 'package:json_annotation/json_annotation.dart';

part 'sample1.g.dart';

@JsonSerializable()
class Sample1 {
@JsonKey(name: "name")
String name;
@JsonKey(name: "age")
int age;

Sample1({this.name, this.age});

@override
String toString() {
return 'Sample1{name: $name, age: $age}';
}

factory Sample1.from(Map<String, dynamic> json) => _$Sample1FromJson(json);

Map<String, dynamic> toJson() => _$Sample1ToJson(this);
}

Mungkin ketika kita menulis kode tersebut maka IDE kita akan menunjukkan error pada beberapa line. Namun, itu wajar karena sebenarnya kode-kode error yang ditunjukkan oleh si IDE adalah kode yang sebenarnya akan terbuat secara otomatis oleh json_serializable.

Beberapa kode yang error

Sekarang coba kita jalankan generatornya dengan perintah berikut.

flutter packages pub run build_runner build

Dan jika berhasil maka kode-kode yang error tadi akan hilang seperti berikut.

Generator berhasil dieksekusi

Jika sudah maka coba kita buka struktur projek programnya maka disitu bisa kita lihat bahwa hasil generator tadi akan membuat file baru bernama sample1.g.dart

File yang terbuat hasil eksekusi generator

Lalu, jika kita coba buka file tersebut maka kodenya seperti berikut.

Kode yang dibuat oleh si generator

Dari kode hasil buatannya bisa kita lihat bahwa sebenarnya kode yang dia buat merupakan kode untuk melakukan parsing manual yang sudah kita pelajari pada artikel Fundamental Parsing JSON in Flutter.

Selanjutnya coba kita tambahkan kode berikut pada file api_service.dart.

Future<Sample1> getSample1() async {
var response = await client.get(
"$baseUrl/sample1",
headers: {"accept": "application/json"},
);
if (response.statusCode == 200) {
var responseJson = json.decode(response.body);
return Sample1.from(responseJson);
} else {
return null;
}
}

Lalu, kita buka kembali file main.dart dan ubah callback onPressed pada button dengan teks JSON Object seperti berikut.

RaisedButton(
onPressed: () {
apiService.getSample1().then((sample1) {
setState(() {
result = sample1.toString();
});
});
},
child: Text("JSON Object"),
)

Sekarang coba jalankan programnya maka, hasilnya akan menjadi seperti berikut ketika kita tap button JSON Object.

JSON Object

Contoh JSON Object didalam JSON Object

Untuk contoh keduanya silakan kita buat file baru bernama sample2.dart dan isi dengan kode berikut.

import 'package:json_annotation/json_annotation.dart';
part 'sample2.g.dart';

@JsonSerializable()
class Sample2 {
String name;
int age;
Github github;

Sample2({this.name, this.age, this.github});

@override
String toString() {
return 'Sample2{name: $name, age: $age, github: $github}';
}

factory Sample2.fromJson(Map<String, dynamic> json) => _$Sample2FromJson(json);

Map<String, dynamic> toJson() => _$Sample2ToJson(this);

}

@JsonSerializable()
class Github {
String username;
int repository;

Github({this.username, this.repository});

@override
String toString() {
return 'Github{username: $username, repository: $repository}';
}

factory Github.fromJson(Map<String, dynamic> json) => _$GithubFromJson(json);

Map<String, dynamic> toJson() => _$GithubToJson(this);

}

Lalu, kita jalankan perintah build runner-nya.

flutter packages pub run build_runner build

Sekarang kita tambahkan kode berikut didalam file api_service.dart.

Future<Sample2> getSample2() async {
var response = await client.get(
"$baseUrl/sample2",
headers: {"accept": "application/json"},
);
if (response.statusCode == 200) {
var responseJson = json.decode(response.body);
return Sample2.fromJson(responseJson);
} else {
return null;
}
}

Lalu, kita buka lagi file main.dart dan ubah kode didalam callback onPressed button dengan teks JSON Object didalam JSON Object.

RaisedButton(
onPressed: () {
apiService.getSample2().then((sample2) {
setState(() {
result = sample2.toString();
});
});
},
child: Text("JSON Object didalam JSON Object"),
),

Sekarang coba jalankan lagi programnya maka ketika kita tap button JSON Object didalam JSON Object outputnya akan menjadi seperti berikut.

JSON Object didalam JSON Object

Contoh JSON Array

Lalu, untuk contoh berikutnya kita akan melakukan parsing JSON Array. Untuk langkah-langkahnya hampir sama seperti pada contoh-contoh sebelumnya yaitu kita buat terlebih dahulu file baru bernama sample3.dart dan isi dengan kode berikut.

import 'package:json_annotation/json_annotation.dart';
part 'sample3.g.dart';

@JsonSerializable()
class Sample3 {
String name;
int age;
List<String> hobi;

Sample3({this.name, this.age, this.hobi});

@override
String toString() {
return 'Sample3{name: $name, age: $age, hobi: $hobi}';
}

factory Sample3.fromJson(Map<String, dynamic> json) => _$Sample3FromJson(json);

Map<String, dynamic> toJson() => _$Sample3ToJson(this);

}

Lalu, kita tambahkan kode berikut di file api_service.dart seperti berikut.

Future<Sample3> getSample3() async {
var response = await client.get(
"$baseUrl/sample3",
headers: {"accept": "application/json"},
);
if (response.statusCode == 200) {
var jsonResponse = json.decode(response.body);
return Sample3.fromJson(jsonResponse);
} else {
return null;
}
}

Dan terakhir kita ubah kode didalam callback onPressed button dengan teks JSON Array seperti berikut.

RaisedButton(
onPressed: () {
apiService.getSample3().then((sample3) {
setState(() {
result = sample3.toString();
});
});
},
child: Text("JSON Array"),
)
JSON Array

Contoh JSON dengan data kompleks

Dan berikut sebagai contoh terakhir mengenai penggunaan json_serializable. Kita buat file sample4.dart dan isi dengan kode berikut.

import 'package:json_annotation/json_annotation.dart';
part 'sample4.g.dart';

@JsonSerializable()
class Sample4 {
String name;
int age;
List<String> hobi;
Github github;
List<Article> articles;

Sample4({this.name, this.age, this.hobi, this.github, this.articles});

@override
String toString() {
return 'Sample4{name: $name, age: $age, hobi: $hobi, github: $github, articles: $articles}';
}

factory Sample4.fromJson(Map<String, dynamic> json) => _$Sample4FromJson(json);

Map<String, dynamic> toJson() => _$Sample4ToJson(this);

}

@JsonSerializable()
class Github {
String username;
int repository;

Github({this.username, this.repository});

@override
String toString() {
return 'Github{username: $username, repository: $repository}';
}

factory Github.fromJson(Map<String, dynamic> json) => _$GithubFromJson(json);

Map<String, dynamic> toJson() => _$GithubToJson(this);

}

@JsonSerializable()
class Article {
int id;
String title;
String subtitle;

Article({this.id, this.title, this.subtitle});

@override
String toString() {
return 'Article{id: $id, title: $title, subtitle: $subtitle}';
}

factory Article.fromJson(Map<String, dynamic> json) => _$ArticleFromJson(json);

Map<String, dynamic> toJson() => _$ArticleToJson(this);

}

Lalu, kita tambahkan lagi kode berikut didalam file api_service.dart.

Future<Sample4> getSample4() async {
var response = await client.get(
"$baseUrl/sample4",
headers: {"accept": "application/json"},
);
if (response.statusCode == 200) {
var jsonResponse = json.decode(response.body);
return Sample4.fromJson(jsonResponse);
} else {
return null;
}
}

Dan selanjutnya kita ubah kode didalam callback onPressed dari button dengan teks JSON dengan data kompleks seperti berikut.

RaisedButton(
onPressed: () {
apiService.getSample4().then((sample4) {
setState(() {
result = sample4.toString();
});
});
},
child: Text("JSON dengan data kompleks"),
)
JSON dengan data kompleks

Kesimpulan

Mungkin kita bertanya-tanya sebenarnya apa tujuan kita mempelajari generator json serializable ini dimana, kalau kita lihat-lihat sebenarnya kode yang dibuat oleh si generator pun sebenarnya kode-kode parsing manual yang bisa kita tulis sebagai developer. Jadi, sebenarnya tujuan kita mempelajari json serializable ini adalah agar mempermudah kita sebagai developer dalam mengurangi kode yang kita ketik. Mungkin untuk saat ini kita belum merasakan manfaat dari generator json serializable ini karena aplikasi yang kita handle belum sekompleks yang kita bayangkan. Coba kita bayangkan jika respon JSON dari endpoint-nya memiliki banyak field maka, ini jelas akan memakan waktu kita sebagai developer untuk menulis kode parsing-nya. Jadi, kesimpulannya adalah json serializable berfungsi untuk membantu kita mengurangi pengetikan kode yang panjang untuk melakukan parsing json. Untuk kode lengkapnya dari artikel ini bisa dilihat di Github ya.

--

--