JSON 데이터 처리

    모바일 개발자가 Flutter를 접하고 처음 네트워크 통신을 구현하고자 할 때, Gson, Jackson, Moshi와 비슷한 기능을 하는 라이브러리를 가장 먼저 찾지 않을까 합니다. 

    Json 파일을 데이터 모델로 변경하는 것은 어렵다 힘들다 보다는 귀찮고 손이 많이 가기 때문입니다. 

     

    서론이 길었는데, 

    결론은 Flutter에서는 Gson과 같은 라이브러리는 없습니다. 

     

    이유는 Flutter에서는 Runtime Reflection(리플렉션)을 사용하지 않습니다.

    이는 Dart에서 지원하는 Tree Shaking의 기능을 우선 시하기 때문입니다. Tree Shaking은 빌드 시에 불필요한 코드를 제거하여 앱의 사이즈를 최적화 시켜주는 기능을 가집니다.

    여기서 문제는 런타임 시에 리플렉션으로 사용되는 부분이 어딘지 알 수가 없기 때문에 Tree Shaking의 기능은 쓸모가 없게 됩니다. 

     

    따라서 Flutter에서는 3 가지 방식을 제안합니다. 

     

    하기 Json 데이터로 3가지 방식을 이야기해 봅니다. 

    {
      "name": "홍길동",
      "email": "gildong@example.com"
    }

     

    1. dart:convert를 이용 

    Map<String, dynamic> user = jsonDecode(jsonString);

    굉장히 심플합니다. 

    그런데 잘 보시면 jsonDecode()는 Map<String, dynamic>을 리턴하여, dynamic이라는 자료형으로 인해 여러 문제(타입 에러, 가독성, 컴파일 타임 오류)가 발생할 수 있습니다. 또한 json의 필드 명에 대한 정보가 없으면 접근할 수도 없습니다. 

    소규모 프로젝트에서 사용하라고 하지만 사실 다른 대안이 필요합니다. 

     

    2. Model 클래스에서 Json serializable(직렬화)

    class User {
      final String name;
      final String email;
    
      User(this.name, this.email);
    
      User.fromJson(Map<String, dynamic> json)
          : name = json['name'],
            email = json['email'];
    
      Map<String, dynamic> toJson() =>
        {
          'name': name,
          'email': email,
        };
    }
    Map userMap = jsonDecode(jsonString);
    var user = User.fromJson(userMap);
    

    1번에서의 생각했던 여러 문제점들이 해소된 모습입니다. 타입도 명확하고 필드에 대한 가독성과 컴파일 타입의 오류 또한 좋아졌습니다. 

    필자가 2번과 같은 방식으로 개발을 진행해본 경험으로는 저~~엉말 불편하고 귀찮습니다. 

    지금 동일한 타입의 필드 2개로 위와 같은 모델의 코드양이라면 몇 개만 더 추가되더라도 손이 많이 갑니다. 

    그래서 3번의 방법이 나왔습니다. 

     

    3. Json Serializable 

    결론으로는 하기의 라이브러리를 통해 코드 생성 자동화를 이용합니다. 

    https://pub.dev/packages/json_serializable

     

    json_serializable | Dart Package

    Automatically generate code for converting to and from JSON by annotating Dart classes.

    pub.dev

    설치와 사용법은 위에 링크에 잘 설명되어 있으니, 뭐가 달라졌나 보겠습니다. 

    import 'package:json_annotation/json_annotation.dart';
    
    part 'user.g.dart';
    
    @JsonSerializable()
    
    class User {
      User(this.name, this.email);
    
      @JsonKey(name: 'name')
      String userName;
      String email;
      
      factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
    
      Map<String, dynamic> toJson() => _$UserToJson(this);
    }

     

    굉장히 축소되었으며, 개발자의 휴먼 에러가 발생될 부분이 현저하게 줄어들었습니다. 

    심지어는 필드명의 변경도 아주 쉬워 졌습니다. 

    앞으로 더 발전하겠으나 위의 방식이 현재 Flutter에서 추천하는 방식입니다. 

     

    위의 내용은 하기 사이트에서 내용을 요약 및 정리하여 작성하였습니다. 

    https://flutter-ko.dev/docs/development/data-and-backend/json

     

    JSON과 직렬화

    어느 시점부터 웹 서버와 통신하지 않거나 구조화된 데이터를 적절하게 보관하지 않는 모바일 앱을생각하기 어려워졌습니다. 네트워크와 연결된 앱을 제작할 때, 결국에는 제법 괜찮은 JSON을사

    flutter-ko.dev

     

    댓글