플러터로 앱을 개발하다 보면 백엔드와 데이터를 주고받는 일이 필수입니다. 서버에서 데이터를 받아오거나, 서버로 데이터를 전송할 때 대부분 JSON이라는 형식을 사용하게 되죠. 하지만 JSON은 단순한 문자열일 뿐이고, 우리가 실제로 사용하는 건 Dart의 객체입니다. 그렇다면 이 둘을 어떻게 자연스럽게 오갈 수 있을까요?
바로 이때 필요한 것이 직렬화(Serialization)와 역직렬화(Deserialization)입니다. 이번 글에서는 Dart에서 JSON 데이터를 어떻게 직렬화하고 역직렬화하는지, 그리고 그 과정에서 어떤 점들을 주의해야 하는지 예제와 함께 알아보겠습니다.
직렬화와 역직렬화란 무엇인가?
먼저 용어부터 정확히 짚고 넘어갈 필요가 있습니다.
- 직렬화(Serialization)란, 객체를 서버에 보내거나 로컬에 저장할 수 있도록 Map → JSON 문자열 형식으로 바꾸는 것을 말합니다.
- 반대로 역직렬화(Deserialization)란, JSON 문자열 → Map → Dart 객체로 되돌리는 과정을 뜻합니다.
Dart에서 이 과정을 도와주는 것이 바로 dart:convert 패키지입니다. 이 안에는 jsonEncode()와 jsonDecode()라는 두 개의 핵심 함수가 들어있어요.
예를 들어, 아래는 Map을 JSON 문자열로 직렬화하는 코드입니다.
import 'dart:convert';
void main() {
Map<String, dynamic> myInfo = {
"name": "이지원",
"age": 20,
};
String jsonString = jsonEncode(myInfo);
print(jsonString); // {"name":"이지원","age":20}
}
그리고 JSON 문자열을 다시 Map으로 바꾸는 역직렬화 과정은 이렇게 됩니다.
import 'dart:convert';
void main() {
String jsonString = '{"name": "이지원", "age": 20}';
var map = jsonDecode(jsonString);
print(map); // {name: 이지원, age: 20}
print(map.runtimeType); // Map<String, dynamic>
}
이처럼 Dart에서는 Map을 중간다리로 사용해 객체와 문자열(JSON) 사이를 오갈 수 있게 합니다. 이 과정을 잘 이해하고 있어야 나중에 서버 연동이나 로컬 데이터 저장에서 무리가 없습니다.
Dart 객체를 JSON과 주고받기
Map으로 JSON을 다루는 것만으로도 간단한 앱을 만드는 데는 큰 문제가 없지만, 실제 개발에서는 각 데이터를 하나의 클래스(객체)로 정의해서 쓰는 것이 훨씬 안전하고 효율적입니다. 왜냐하면 객체로 만들어야 타입 오류도 줄고, 가독성도 높아지고, 실수도 줄일 수 있기 때문이죠.
예를 들어 아래와 같이 User라는 클래스를 만들어볼 수 있어요.
class User {
User({
required this.name,
required this.age,
});
String name;
int age;
// 역직렬화: JSON(Map)을 → Dart 객체로
User.fromJson(Map<String, dynamic> json)
: this(
name: json['name'],
age: json['age'],
);
// 직렬화: Dart 객체를 → JSON(Map)으로
Map<String, dynamic> toJson() {
return {
"name": name,
"age": age,
};
}
}
이제 이 클래스를 바탕으로 JSON 문자열을 객체로 바꾸고, 다시 문자열로 바꿔볼 수 있어요.
import 'dart:convert';
void main() {
String jsonString = '{"name": "이지원", "age": 20}';
// Step 1: JSON 문자열을 Map으로
Map<String, dynamic> jsonMap = jsonDecode(jsonString);
// Step 2: Map을 Dart 객체(User)로
User user = User.fromJson(jsonMap);
print(user.name); // 이지원
// Step 3: Dart 객체를 다시 JSON(Map)으로
String newJson = jsonEncode(user.toJson());
print(newJson); // {"name":"이지원","age":20}
}
정리하자면,
JSON → jsonDecode() → Map<String, dynamic> → fromJson() → Dart 객체
Dart 객체 → toJson() → Map<String, dynamic> → jsonEncode() → JSON
이런 흐름이 매우 중요합니다.
중첩된 JSON과 복합 객체의 처리
JSON 구조는 단순한 key-value 쌍만으로 이루어져 있지 않고, 내부에 다른 객체나 리스트가 중첩되어 있는 경우가 흔합니다. 이럴 때는 중첩된 구조에 맞춰 Dart 클래스를 여러 개 정의하고, 각 클래스에서 fromJson과 toJson 메서드를 구현해 연결해야 합니다.
예를 들어 다음과 같은 JSON을 살펴볼게요.
{
"name": "오상구",
"age": 7,
"isMale": true,
"favorite_foods": ["삼겹살", "연어", "고구마"],
"contact": {
"mobile": "010-0000-0000",
"email": null
}
}
이를 Dart에서 처리하려면 Pet 클래스와 Contact 클래스를 각각 만들어야 합니다.
class Pet {
final String name;
final int age;
final bool isMale;
final List<String> favoriteFoods;
final Contact contact;
Pet({
required this.name,
required this.age,
required this.isMale,
required this.favoriteFoods,
required this.contact,
});
factory Pet.fromJson(Map<String, dynamic> json) {
return Pet(
name: json["name"],
age: json["age"],
isMale: json["isMale"],
favoriteFoods: List<String>.from(json["favorite_foods"]),
contact: Contact.fromJson(json["contact"]),
);
}
Map<String, dynamic> toJson() {
return {
"name": name,
"age": age,
"isMale": isMale,
"favorite_foods": favoriteFoods,
"contact": contact.toJson(),
};
}
}
class Contact {
final String mobile;
final String? email;
Contact({
required this.mobile,
required this.email,
});
factory Contact.fromJson(Map<String, dynamic> json) {
return Contact(
mobile: json["mobile"],
email: json["email"],
);
}
Map<String, dynamic> toJson() {
return {
"mobile": mobile,
"email": email,
};
}
}
이런 방식으로 구조화된 JSON을 안전하게 관리하고, 코드의 유지보수성을 높일 수 있습니다. 실제 서비스에서는 데이터가 점점 더 복잡해지기 때문에 이러한 클래스 기반 설계가 매우 중요합니다.
마치며...
Dart에서 JSON 데이터를 다루는 방법은 단순히 문자열을 Map으로 바꾸는 것을 넘어서, 객체 지향적으로 관리할 수 있는 구조로 확장해 나가는 것이 핵심입니다. 직렬화와 역직렬화는 서버와 클라이언트 간의 소통을 원활하게 하기 위해 꼭 필요한 개념이며, 이 과정을 잘 설계해두면 API 연동이나 로컬 데이터 저장에서도 안정적으로 데이터를 처리할 수 있습니다.
Flutter 개발을 한다면 JSON과 Dart 객체 간 변환은 더 이상 선택이 아닌 필수입니다. 오늘 소개한 개념들을 잘 익혀두면, 앞으로 다양한 상황에서 유연하게 데이터를 다루는 능력을 갖추게 될 거예요!
세 줄 요약
- Dart에서 JSON을 다루기 위해선 jsonEncode, jsonDecode와 Map 변환 과정을 반드시 거쳐야 해요.
- 안전한 데이터 처리와 유지보수를 위해 fromJson, toJson을 활용한 클래스 기반 구조화가 중요해요.
- 중첩된 JSON 구조도 Dart 클래스 설계로 효율적으로 관리할 수 있으니 연습해 둘 필요가 있어요.
'IT' 카테고리의 다른 글
DIO를 활용한 HTTP 통신 (0) | 2025.04.14 |
---|---|
MVVM 아키텍처와 전역 상태 관리 (0) | 2025.04.11 |
바이브 코딩으로 달라지는 개발 워크플로우 (0) | 2025.04.08 |
바이브 코딩의 시대, 무엇이 달라질까? (0) | 2025.04.07 |
코딩 공부, 이제 순서가 달라진다 (0) | 2025.04.04 |