Back

(Flutter) Model을 베이스로 한 http통신을 구성해 보자

Flutter의 http통신을 아름답게 사용 할 수 없을까?

Retroift같이 Model을 베이스로 한 통신을 구성 할 수 없을까?
자연스러운 비동기 통신을 구성 할 순 없을까?
서드파티 라이브러리를 사용하지 않고, 기본 기능과 문법으로 구성해 볼 수 있지 않을까?

Flutter를 사용하다보니 이와 같은 생각이 들었다.
Dart의 아래 특징을 사용하면 충분히 가능할거란 판단이 들어 시도를 해 보았다.

  1. Generic이 있다. (즉, 타입 체크 및 Model만의 공통 기능 사용이 가능하다.)
  2. factory를 통해 Constructor를 커스텀 할 수 있다.
  3. json(String)을 Map으로 Convert할 수 있는 기능이 있다.
  4. 비동기 작업을 위한 기능(Future)가 있다.

기본 Model클래스 생성

모든 Model객체의 부모가 될 Model 클래스를 생성하자.

class Model {}

Model클래스는 일단 아무런 기능이 필요 없다. 모든 Model객체는 Model클래스를 extends 할 것이고, 이를 통해 1차 타입 체크를 할 것이다.
추가로, 모든 Model객체들에게 공통적인 기능이 필요하다면 해당 클래스에 구현하면 된다.

서버로부터 기본(공통)적인 정보를 저장할 Res 클래스

서버로부터 단순히 요청의 데이터만 받는 경우는 드물다.
응답코드, 응답메시지, 에러코드 등 여러 추가적인 정보를 포함 할 Res 클래스를 생성하자.

이때, 서버로부터 전달 받을 데이터를 Model객체로 하며 Generic을 통해 원하는 모델을 전달받고 타입 검증을 할 수 있도록 구성하자.

실제 사용할 Model클래스 생성

실제 데이터를 포함할 간단한 Model을 생성하자.

factory를 통해 새로운 생성자를 만들고, Map을 전달하면 자동으로 클래스를 생성하도록 구성하자.
또한 새로운 Model 클래스를 구성할 때에도 동일하게 Map으로 객체를 생성할 수 있는 구조를 만들자.

Map을 특정 Model로 변환

각 Model의 factory 생성자 호출하여 Map을 Model로 변환할 함수를 하나 만들도록 하자.

위 함수는 아래와 같이 사용할 수 있을 것 이다.

User myUser = toSpecificModel<User>(jsonMap);

http 통신하여 Model에 담기

이제 본격적으로 http통신을 하여 Model로 받아보도록 하자.
먼저 기본적으로 다음의 라이브러리가 필요하다.
(Dart 개발 팀 공식 라이브러리)

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

위 라이브러리를 추가하면 Client()함수로 http Client객체를 생성할 수 있고, json.decode(String resource)함수를 통해 Json형태의 String을 Map으로 변환할 수 있다.
(http.dart의 response body는 byte 혹은 String으로만 전달 받을 수 있기 때문.)
그 후 Api클래스를 아래와 같이 구성하자.

차근차근 뜯어보자

Api클래스의 get 함수를 분석해보자.

  1. client 객체의 리턴은 비동기(Future)를 통해 전달된다.
    1. 따라서 get 함수 또한, async await를 구성하고 Future를 리턴하도록 구성.
  2. Future는 특정 Model을 담은 Res객체를 반환하도록 구성.
  3. 공통 함수(_genRes, _genUri, genDefaultHeaders) 생성
    1. 기타 http 및 Rest Method(delete, post, put …)에서도 공통적으로 사용할 기능이기에 분리

genRes

genRes함수에는 중요 기능들이 포함되어 있다.

json.decode를 통해 response의 body를 Map으로 변환 후, 먼저 선언하였던 toSepcificModel 함수를 통해 원하는 Model로 Map을 변환하여 최종적으로 Model이 포함된 결과값을 받게 된다!

정리하면…

현재까지 진행사항을 통해, 아래와 같이 http통신을 하고 User Model을 결과값으로 전달 받을 수 있다.

하지만 아직 부족하다!

여기까지 진행해도 Model을 사용한 통신 구성에 문제는 없지만, Dart의 mixin을 활용하여 좀 더 고급스럽게 사용해 보자.

mixin 클래스 생성

먼저, Res 객체가 아닌 Model 자체를 반환받도록 한번 더 함수로 감싸자.
그리고 mixin이기 때문에, 아래와 같이 실 사용이 가능하다.

최종 결과

상태 변경에따라 Widget을 빌드하는 클래스인 _MyHomePageState 클래스에 with UserApi를 추가하여, UserApi mixin에 선언한 함수를 바로 사용 할 수 있게 되었다.
이제 _addUser()를 호출할 때마다 리스트에 새로운 User Model서버와의 통신을 통해 추가되고, 이를 활용해 여러 작업(리스트를 추가한다던지…)이 가능할 것이다!

마무리…

Flutter는 리플렉션을 지원하지 않기에, GSON이나 Jackson와 유사한 라이브러리가 존재하지 않습니다.
그러나 단순 직렬화를 통한 방법은 나름 쉽게 구현할 수 있기에, 위와 같은 방법을 사용하였습니다.
기회가 된다면 json_serializable 을 활용하여 좀 더 짜임새 있게 구성하는 법을 포스트 해 보도록 하겠습니다.

comments powered by Disqus