Flutter Retrofit, JsonSerializable, build_runner(data layer, Clean Architecture, MVVM)
Clean architecture 나 mvvm 등을 보면 Data 부분이 비슷하다.
Data를 사용하고자 하는 곳에서는 해당 data가 web에서 온 건지 내부 DB에서 온 것인지 알고 싶지 않은 것이다.
그래서 딱 Data Layer까지만 구현하고자 한다. (결국 아래만큼만 구현 해보려고 한다.)
JSON을 retrofit 으로 가져와 Repositories를 만들어 아래와 같은 app을 만들어 보려고 한다.
1. Data
이전 글에 작성 되어 있는 My JSON Server에 정의 되어 있는 JSON을 가져와 사용하자
https://truelightn.tistory.com/26
[
{
"title": "title1",
"body": "body1"
},
{
"title": "title2",
"body": "body2body2"
},
{
"title": "title3",
"body": "body3body3body3"
}
]
2. 기본 UI 구성
3. Retrofit 설정
1. 폴더 구조 생성
아래와 같이 폴더 구조를 만들고 외부에서는 repositories를 통해서만 접근이 되도록한다.
2. retrofit package
pubspec.yaml 파일에 retrofit 관련 package를 추가한다.
(dio package에 경우 retrofit에 포함된 것인지 굳이 추가를 안해도된다.)
3. Model
서버로 부터 받은 JSON을 활용하기 위하여 Model을 하나 만들어 준다.
JSON 전환을 위해 xxxFromJson과 xxxToJson이 정의되어야 한다.
생성 하는 방법은 3가지가 있다. 아래 2번과 3번의 방법을 적절하게 활용 하려고 한다.
JsonSerializable 의 경우 처음 접해보는 것인데, buil_runner라는 것을 통해 g.dart라는 파일을 자동 생성해준다.
xxxFromJson과 xxxToJson << 이걸 자동으로 생성해준다.
아래 JSON to Dart tool을 사용하는 이유는 JSON을 class로 만드는게 힘들다
(class에 선언한 변수와 JSON의 key에 오타가 발생하면 에러 찾기 힘듬. 복잡한 JSON구조의 경우 class를 만들기 어려운데 이런걸 금방 해줌)
- 직접 타이핑
- JSON to Dart tool을 활용
- JsonSerializable을 활용
JSON to Dart을 구글링 최상단에 나오는 사이트에 접속
https://javiercbk.github.io/json_to_dart/
JSON을 입력, Class명을 입력 한후 'Generate Dart'해서 나온 소스를 복사하여 아래와 같이 수정한다.
(빨간 줄이 생김)
(아래 처럼 수정 하기 귀찮은데... JSON to JsonSerializable을 누군가 만들지 않을까 한다.(내가 못찾은 건가...))
- pacakge import
- part 추가(추후 자동으로 생성됨)
- 어노테이션추가
- FormJson, ToJson 수정
- 터미널에서 build runner 실행
$ flutter pub run build_runner build
정상적으로 완료가 되면 아래와 같이 터미널에 출력되고 post.g.dart파일이 생성된다.
post.g.dart파일을 확인해 보면 FromJson, ToJson이 재 정의 되어 있는것을 확인 할 수 있다.
참고로 자동 생성된 g.dart파일을 git에 올리느냐 안올리느냐 고민되서 구글링 해보니 레딧에서 이미 투표가 있었다. 근소하게 올린다는 의견이 있고 나도 그게 맞는거 같아서 올렸다.
https://www.reddit.com/r/FlutterDev/comments/kazxo0/do_you_add_gdart_files_to_gitignore/
4. rest client 생성
아래와 같이 무지성으로 코드를 작성한 후 build runner을 실행하면 위 와 비슷하게 g.dart 파일이 생성 된다.
추후 추가되는 api들에 대해서 @GET,POST등으로 쭉 써내려가면됨.
(해당 코드가 변경 될때마다 build runner을 실행해야함, 이게 귀찮으면 파일이 수정될때마다 자동으로 g.dart파일이 생성되도록 설정 할 수 있음)
5. Repositories
retrofit을 검색 해보면 아래 주석 처리 코드가 있고 DI를 이용해서 구현 하게끔 되어 있다.
굳이 DI를 적용하고 싶지 않아서 .create()를 만들어서 restclient를 가져오려고한다.
api는 기본적으로 Future타입으로 return을 해야 한다.
<Post>를 <HTTPResponse<Post>>로 변경하면 http response code(200, 401이런거)를 사용하여 좀 더 세밀하게 처리 할 수 잇다.
개인적으로 DI는 TDD를 위해서 있는거 같다. 결국 객체를 생성해서 생성자를 넣어주는 것이고, 이것이 보일러플레이트가 되니깐 DI를 해주는 툴들이 있다. TDD는 당연히 유지보수상 좋지만, 간단한 프로젝트에서는 불필요 하다고 생각한다. 학습도 해야하며, 개인적으로 소스코드를 보기도 힘들다고 생각한다.(api호출 흐름을 찾아가기가 힘듬)
6. 사용
main에 initState()에서 repo를 생성한다. (위에 repositories의 주석으로 구현했으면 main에서 restclient를 생성해서 넣어줘야 하지만 매번 이러기 귀찮으니 DI툴을 쓰거나 위에처럼 Repositories에서 client를 생성 하면 된다.)
Git Hub
이쁘게 커밋을 하고 싶었으나 뻘짓을 많이하여 이쁘게 못올림..
git@github.com:truelightn/ex_flutter.git
https://medium.com/@fakhiradevina/flutter-tdd-clean-architecture-272373727699
https://astar-digital.org/flutter-and-clean-architecture
https://ichi.pro/ko/android-mvi-ban-eung-hyeong-akitegcheo-paeteon-128530942790279
zvasv