본문 바로가기
개발/플러터(Flutter)

[플러터(Flutter)] - jsonserializable로 API요청 최적화하기

by 수인분당선 2024. 10. 6.
반응형

안녕하세요

오늘은 jsonserializable 라이브러리를 배울 예정입니다.

 

 

이전에 json 및 formdata타입의 데이터를 API 통신으로 전송하고 받는 방법에 대해서 글을 작성한 적이 있습니다.

https://suin9643.tistory.com/7

 

[플러터(Flutter)] - Http,dio 라이브러리로 json 타입, formdata타입 데이터 전송(POST)하기

오늘은 데이터를 전송하는 방법을 알아보겠습니다! json 타입 데이터 전송(POST) 예제로 작성한 코드는 회원가입을 통해 닉네임 등의 회원 정보를 서버로 전송하고 토큰을 통해 얻은 이메일을 받

suin9643.tistory.com

기본적으로 API 에 데이터를 요청하는 작업은 위의 내용으로 진행됩니다.

하지만 요청해야하는 API의 개수가 10개,,20개,,수백개로 늘어나게 된다면 위의 방법으로는 그때마다 API 코드를 복제하여 수십 수백개의 중복되는 코드를 생성해야만 합니다.

그런 불필요한을 줄이기 위해서 jsonserializable가 탄생했습니다.

이 jsonserizalizable를 통해서 JSON 데이터를 쉽게 직렬화(serialize,객체 데이터를 JSON으로 변환) 및 역직렬화(deserialize, JSON데이터를 객체로 변환)하는 방법을 배워봅시다


1. 라이브러리 추가하기

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

이 라이브러리는 특이하게도 독립적으로 설치하여 사용되지 않습니다. 

라이브러리 제공 사이트를 참고하면 Setup가 참조되어있는 것을 볼 수 있으실텐데, 이를 참고하여 

https://github.com/google/json_serializable.dart/tree/master/example

 

json_serializable.dart/example at master · google/json_serializable.dart

Generates utilities to aid in serializing to/from JSON. - google/json_serializable.dart

github.com

dependencies:
  json_annotation: ^4.9.0

dev_dependencies:
  build_runner: ^2.3.3
  json_serializable: ^6.8.0

serializable말고도 두개의 라이브러리를 더 필요로 한다는 것을 알 수 있습니다.

https://pub.dev/packages/json_annotation

 

json_annotation | Dart package

Classes and helper functions that support JSON code generation via the `json_serializable` package.

pub.dev

 

https://pub.dev/packages/build_runner

 

build_runner | Dart package

A build system for Dart code generation and modular compilation.

pub.dev

 

아래 두가지를 함께 넣어줍시다. 

그렇게 하면 셋팅은 완료!

 

2. 코드 작성하기

import 'package:json_annotation/json_annotation.dart';

part 'model.g.dart'; //.g.dart파일 생성을 위한 파트 추가

@JsonSerializable() //jsonSerializable를 통한 JSON변환
class Model  {
  final String id;
  final String name; 
  final List<String> tags; 
  final int num;

  Model({
    required this.id,
    required this.name,
    required this.tags,
    required this.num,
  });

//json의 기본 데이터타입은 Map<String, dynamic>이기에 사용됨
  factory Model.fromJson(Map<String, dynamic> json) //JSON-> 데이터로의 변환
  =>_$ModelFromJson(json);

  Map<String,dynamic> toJson() => _$ModelToJson(this); //데이터->JSON으로의 변환
}

3. 빌드하기

위에서 작성한 .g파일을 생성하기 위해 파트파일을 생성하는 빌드 코드를 터미널에 입력합니다.

flutter pub run build_runner build

코드가 제대로 짜여진 상태에서 해당 명령어를 입력하면

정상적으로 .g.dart파일이 생성되는 것을 볼 수 있습니다.

 

추가적으로

flutter pub run build_runner watch

해당 코드를 입력하면 실시간으로 작성한 코드에 맞게 코드가 업데이트되므로,

이 코드도 잘 활용해주면 유용합니다!

 

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'model.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Model _$ModelFromJson(Map<String, dynamic> json) =>
    Model(
      id: json['id'] as String,
      name: json['name'] as String,
      tags: (json['tags'] as List<dynamic>).map((e) => e as String).toList(),
      num: (json['num'] as num).toInt(),
    );

Map<String, dynamic> _$ModelToJson(Model instance) =>
    <String, dynamic>{
      'id': instance.id,
      'name': instance.name,
      'tags': instance.tags,
      'num': instance.num,
    };

여기서 생성된 .g.dart파일을 둘러보면,

이전에 저희가 수기로 작성한 API요청 코드들이 자동으로 잘 생성되어 있는 것을 볼 수 있습니다.

 

4. 특수 변환 넣기

추가적으로, JSON을 데이터로 변경할 때, 특수한 위젯 및 타입으로 변환해야 하는 경우가 간혹있는데,

그런 예외적인 경우에는 어떤 방식으로 처리하여야 하는지 알아보도록 하겠습니다.

import 'package:json_annotation/json_annotation.dart';

part 'model.g.dart'; //.g.dart파일 생성을 위한 파트 추가

@JsonSerializable() //jsonSerializable를 통한 JSON변환
class Model  {
  final String id;
  final String name; 
  final List<String> tags; 
  @JsonKey(fromJson: pathToUrl) //여기!
  final String Url;
  final int num;

  Model({
    required this.id,
    required this.name,
    required this.Url,
    required this.tags,
    required this.num,
  });

  factory Model.fromJson(Map<String, dynamic> json) //JSON-> 데이터로의 변환
  =>_$ModelFromJson(json);

  Map<String,dynamic> toJson() => _$ModelToJson(this); //데이터->JSON으로의 변환
}

  static pathToUrl(String value){  //jsonKey에 들어갈 함수는 무조건 static여야함
    return "http://$ip$value}";
  }

특수 변환의 경우, 따로 @JsonKey 키워드와 함께 실행될 변환함수를 입력해줍니다.

여기서의 함수는 반드시 static를 반환해주어야 합니다.

@JsonKey 어노테이션에서 사용하는 fromJson과 toJson 함수는 모델 클래스에서 자동으로 생성되는 코드와 연동되기 때문에, 해당 함수들은 인스턴스 메서드가 아니라 클래스 레벨에서 사용될 수 있어야 합니다. 즉, 인스턴스 생성 없이도 호출될 수 있어야 합니다.

 

추가로 @JsonKey는 fromJson과 toJson 외에도 다양한 옵션들을 지원합니다.

  • ignore: 특정 필드를 JSON 직렬화에서 제외할 때 사용
  • defaultValue: JSON에 해당 필드가 없는 경우 사용할 기본값을 설정
  • includeIfNull: 필드가 null일 때 해당 필드를 포함할지 여부를 설정

등 여러가지 기능을 가지고 있으므로 해당 옵션들을 잘 활용하면 좋은 코드를 짤 수 있습니다!

 

 

코드를 원하는대로 잘 변경해준 이후, 다시 빌드를 실행하면 다시 .g.dart파일이 의도한대로 잘 변경되는 것을 알 수 있습니다!

 

추가로, 주의해야 할 점은, .g.dart 파일은 수정하면 안됩니다!!

수정해야하는 경우가 생기면 .dart파일을 수정하고 다시 빌드를 업데이트하면 자동으로 적용이 되니 절대 건드리시면 안됩니다!

 


이제 저희는 중복되는 코드를 일일히 작성할 필요 없이 편하게 JSON변환이 가능하게 되었습니다!

추가적인 내용이 부족하거나 질문할 부분이 있다면 댓글 부탁드립니다

감사합니다.

반응형

 

반응형