Back

(Flutter) Json안의 Object와 Array도 Model로 사용하자

Json안의 Obejct와 Array도 Model Class로 사용하고 싶다!

지난 포스트 에서 http 통신의 결과값(Json)을 Model Class로 받는 방법에 대해 설명하였다.
해당 포스트에선 예시로 단순한 Json 형태를 들었지만, 실제 현장에서는 훨신 복잡한
(Json 안에 또다른 Object 혹은 Array가 있는) 형태의 Json들을 다루게 된다.
이런 경우에도 Model Class로 Json의 내용을 치환하여 사용해 보자!

필요한 Model을 만들자

다음과 같은 Json을 다룬다고 가정해 보자.

{ 
    id: "user",
    name: "I AM USER",
    address: [
        {
            name: "home",
            detail: { first: "korea", second: "seoul" },
            zipCode: { old: { code: "123456" }, new: { code: "7890" } }
        }
    ] 
}

지난 포스트의 User Model에서 address가 추가된 형태이다.
address는 List 형태로서 복수개의 Object를 가질 수 있다.
각각의 Object는 이름 - name(String), 상세 주소 - detail(Object), 우편번호 - zipCode(Object) 가 있으며,
zipCode의 각각 항목은 또다른 Object로 구성되어 있다.
먼저 복잡한 이 Json의 각 항목을 Model로 작성해 보자.

/// 가장 최상위 User Model
class User extends Model {
  final String id;
  final String name;
  final List<Address> address;
}

/// List 내의 각 주소 Model
class Address extends Model {
  final String name;
  final Map<String, ZipCode> zipCode;
  final AddressDetail detail;
}

/// 상세 주소 Model
class AddressDetail extends Model {
  final String first;
  final String second;
}

/// 우편 번호 code Model
class ZipCode extends Model {
  final String code;
}

총 3가지의 케이스를 기준으로 Model을 구성하였다.

  1. Array안의 Object를 다룰 경우 - final List<Address> address;
  2. Object를 바로 Model로 다루는 경우 - final AddressDetail detail;
  3. Object안의 또다른 Object가 있어, Map으로 다루는 경우 - final Map<String, ZipCode> zipCode;

이어서 Json을 각 Model Class 안에 옮기는 작업을 진행해 보자.

Array와 Object를 Model로 변환

지난 포스트에선 아래의 함수를 구성하였다.

먼저, toSpecificModel함수에 이번에 새로 추가한 함수들을 Switch조건에 포함시키자.

다음으로 Array -> List<Model>, Object -> Map<String, Model>으로 변환시킬 함수를 제작하자.
(Object -> Map의 경우에는, toSpecificModel을 사용하면 된다.)

Array를 List로 변환할 toSpecificModelList 함수

Object를 Map<String, Model>로 변환할 toSpecificModelMap 함수

마지막으로, 각 Model들의 생성자를 구성하자.

이때, 각 Model이 포함 할 또다른 Model들을 위에 구성한 함수들을 사용하여(중요) 생성하도록 하자!

테스트

지난 포스트의 response를

{ 
    id: "user",
    name: "I AM USER",
    address: [
        {
            name: "home",
            detail: { first: "korea", second: "seoul" },
            zipCode: { old: { code: "123456" }, new: { code: "7890" } }
        }
    ] 
}

로 변경하고 getNewUser 함수를 아래와 같이 수정하여 테스트를 진행하자.

Future<User?> getNewUser() async {
    Res<User> res = await _api.post<User>(url: "/getUser");
    final user = res.data; // 유저 데이터
    final firstAddress = user?.address[0]; // Address Model
    final firstAddressName = firstAddress?.name; // Address Model의 name 상수
    final oldZipcode = firstAddress?.zipCode["old"]; // zipCode Object의 "old" Object
    final firstAddressDetail = firstAddress?.detail; // Address Model의 detail Model
    print("message: ${res.message}"); // "success!!"
    print("serverCode: ${res.serverCode}"); // 100
    print("statusCode: ${res.statusCode}"); // 200
    print("addressName: $firstAddressName"); // home
    print("addressDetail: ${firstAddressDetail?.first}"); // korea
    print("oldZipCode: ${oldZipcode?.code}"); // 123456
    print("isSuccess: ${res.isSuccess}"); // true
    print("isException: ${res.isException}"); // false
    return res.data;
}

콘솔 창에 아래와 같이 출력될 것 이다.

message: success!!
serverCode: 100
statusCode: 200
addressName: home
addressDetail: korea
oldZipCode: 123456
isSuccess: true
isException: false

마무리

Reflection을 할 수 있는 dart:mirror 라이브러리를 활용하면, GsonConverter와 같이 자동으로 Json의 내용을 Model Class의 구조에 맞게 담아주게 구성 할 수 있을것이다.
하지만, Reflection을 하지 않고도 Dart의 문법만으로도 충분히 실 사용이 가능할 정도(크게 러닝커브가 크지 않으면서) Json을 Model class로 사용 할 수 있도록 구성 해 보았다.
다음 포스트에는 Web과 Native의 플랫폼별 인터페이스를, 동일한 구조로 사용하는 과정을 포스트해 보도록 하겠다.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus