# จัดการ JSON ใน Dart ง่ายนิ้ดดดเดียว
#Dev#Dart#Flutter#Json#Libraryเดี๋ยวนี้ไม่ว่าเราจะเรียก API หรือ Service ใดๆ ก็มักจะมีการส่งค่ากลับมาในรูปแบบของ JSON (Javascript Object Notation) กันหมดแล้ว ในบทความนี้เราจะมากล่าวถึงการจัดการกับ JSON พวกนี้กันครับ

# พื้นฐาน
เราสามารถแปลงค่าไปมาระหว่าง Map ในภาษา Dart กับ JSON String ได้ด้วยคำสั่ง
String jsonEncode(object )
และ dynamic jsonDecode(String)
เช่น
import "dart:convert";
void main() {
var userJson = '{"name":"Intception","page": "Intception Hideout"}';
Map<String, dynamic> userMap = jsonDecode(userJson);
print(userMap["name"]);
print(userMap["page"]);
var userJsonEncoded = jsonEncode(userJson);
print(userJsonEncoded);
}
จะได้ผลลัพธ์
Intception
Intception Hideout
"{\"name\":\"Intception\",\"page\": \"Intception Hideout\"}"
แปลงค่า Map<String, dynamic>
ถ้าเราอยากได้ Map<String, String> เราสามารถใช้ Map<String, String>.from(userMap) ในการแปลงค่าได้
** โดย userMap มีชนิดเป็น Map<String, dynamic>
# แยกข้อมูลทำเป็น Model
คนที่มาทำงานต่อก็สามารถรู้ได้ถึงโครงสร้างข้อมูลได้ทันทีหลังจากดู Model
การที่เราทำงานกับ JSON นั้นมันจะสร้างความลำบากให้เราได้ถ้าเราเอาสิ่งที่ได้จาก jsonDecode มาใช้โดยตรง เพราะ ตัว IDE หรือ Editor ที่เราใช้ มันจะไม่บอกว่าตัวแปรของเรามีสมาชิกอะไรบ้างอย่างเช่นตัวอย่างด้านล่าง
IDE ของเราจะไม่รู้ว่า userMap มีสมาชิกอะไรบ้าง
import "dart:convert";
void main() {
var userJson = '{"name":"Intception","page": "Intception Hideout"}';
Map<String, dynamic> userMap = jsonDecode(userJson);
print(userMap["name"]); // IDE จะไม่รู้ว่า userMap ของเรามีสมาชิกชื่ออะไรให้เรียกได้บ้าง
}
เราจึงจะทำการสร้าง class เพื่อที่จะมาจัดการกับข้อมูล แทนที่จะไปใช้ Map โดยตรง
import 'dart:convert';
class User {
String name;
String pageName;
User(this.name, this.pageName);
User.fromJson(Map<String, dynamic> json)
: name = json['name'],
pageName = json['page']; // ผมสามารถเปลี่ยนชื่อไม่ต้องใช้ page ก็ได้
Map<String, dynamic> toJson() => {'name': name, 'page': pageName};
}
void main() {
var userJson = '{"name":"Intception","page": "Intception Hideout"}';
var user = User.fromJson(jsonDecode(userJson));
print(user.name);
print(user.pageName);
var userJsonEncoded = jsonEncode(user.toJson());
print(userJsonEncoded);
}
เมื่อรันดูก็จะต้องได้ผลที่เหมือนเดิมครับ แต่สิ่งที่เราได้เพิ่มมาก็คือ Code Completion นั่นเอง

# ใช้ตัวช่วยสร้าง Model ที่รองรับ JSON
ทีนี้ในโปรเจคที่ใหญ่มากขึ้น การมาสร้าง Model ให้รองรับ JSON ด้วยนั้น อาจจะมีความเยอะและเหนื่อยมากเกินไป
เราจึงจะมาใช้ Library ที่ช่วยในการ Generate Code ให้กับเรากันครับ โดย Library ที่จะใช้นั้นมีชื่อว่า build_runner และ json_serializable
สามารถเริ่มติดตั้งได้โดยการเพิ่ม dependencies ตามนี้ครับ
...
dependencies:
json_annotation: ^3.0.0
dev_dependencies:
build_runner: ^1.0.0
json_serializable: ^3.2.0
...
สิ่งถัดไปที่เราจะทำก็คือแยก Model ของเราออกมาใส่ไฟล์แยกครับ ในที่นี้คือไฟล์ models/user.dart
import 'package:json_annotation/json_annotation.dart';
// File ที่จะถูก Generate นั้นจะอยู่ในไฟล์ user.g.dart ครับ
// ชื่อไฟล์/ชื่อ Class/ ชื่อ part ไฟล์ จะเป็นชื่อเดียวกัน *.g.dart
part 'user.g.dart';
()
class User {
String name;
(name: 'page')
String pageName;
User(this.name, this.pageName);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
@JsonSerializable() - เป็นการบอกให้ dart รู้ว่าเราต้องการให้มันสร้าง fromJson กับ toJson ให้เราโดยอ้างอิง Class property และ Constructor
@JsonKey(name: '...') - ไว้กำหนดว่า Class Property นี้ต้องการจะรับค่าจาก Key ชื่ออะไรใน JSON
เมื่อเราสั่งคำสั่ง
flutter pub run build_runner build
หากขี้เกียจกด build บ่อยๆ สามารถใช้คำสั่งนี้แทนได้ครับ
flutter pub run build_runner watch
ก็จะเกิดไฟล์ชื่อ user.g.dart
ขึ้นมาครับ
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
User _$UserFromJson(Map<String, dynamic> json) {
return User(
json['name'] as String,
json['page'] as String,
);
}
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
'name': instance.name,
'page': instance.pageName,
};
ซึ่งประหยัดเวลาในการเขียนส่วนของการแปลง JSON ได้อย่างมากเลยทีเดียว
ทีนี้ไฟล์ main.dart
ของเราก็จะเหลือแค่
import 'dart:convert';
import 'models/user.dart';
void main() {
var userJson =
'{"name":"Intception","page": "Intception Hideout"}';
var user = User.fromJson(jsonDecode(userJson));
print(user.name);
print(user.pageName);
var userJsonEncoded = jsonEncode(user.toJson());
print(userJsonEncoded);
}
เมื่อรันแล้วก็ยังได้ผลเหมือนเดิมอยู่