Edited at
FlutterDay 20

【Flutter】JSONをデコードする

この記事は Flutter Advent Calendar 2018 - Qiita の20日目の記事です。


概要

FlutterにおけるJSONのデコード(エンコード)についてまとめます。


まとめ

小規模なプロジェクトでは手動デコードでもいいかもしれませんが、中規模以上のプロジェクトではコードジェネレーター(json_serializable)を使ったほうが良さそうです。


やり方


手動デコードの場合

Flutterはデフォルトで dart:convert というパッケージが入っているので

JsonCodec class で簡単にシリアライズできます。


sample.json

{

"name": "John Smith",
"email": "john@example.com"
}


main.dart

Map<String, dynamic> user = json.decode(json);

print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');


json.decode() の戻り値の型は Map<String, dynamic> なので実行するまでJSONのValueがどの型になるかは分かりません。

また、デコード処理するロジックにキー名を書かないといけません。そのままStringで書いているのでtypoする可能性があります。


モデルクラスを使う場合

User というモデルクラスを用意し User.fromJson() / User.toJson() を定義します。


user.dart

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,
};
}



main.dart

Map userMap = json.decode(json);

var user = new User.fromJson(userMap);

print('Howdy, ${user.name}!');
print('We sent the verification link to ${user.email}.');


エンコード・デコードのロジックをモデルクラスに内包することができました。

呼び出し側ではnameemailをStringではなくUserクラスのフィールドを参照しているので、typoしていた場合はコンパイルエラーで気がつくことができます。


コードジェネレーターライブラリを使う場合

pubspec.yamljson_annotationjson_serializableを追加します。


pubspec.yaml

dependencies:

json_annotation: ^2.0.0

dev_dependencies:
build_runner: ^1.0.0
json_serializable: ^2.0.0


Userクラスを定義してJsonSerializableアノテーションを付与します。


user.dart

import 'package:json_annotation/json_annotation.dart';

// ジェネレートされたクラスからUserクラスのprivateメンバ変数にアクセスするため
part 'user.g.dart';

@JsonSerializable()
class User {
User(this.name, this.email);

String name;
String email;

// _$UserFromJsonが生成される
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

// _$UserToJsonが生成される
Map<String, dynamic> toJson() => _$UserToJson(this);
}


FlutterプロジェクトのRootでコマンドラインで以下を実行。()

flutter packages pub run build_runner build

実行後、コードが生成されるので前述したやり方と同様にエンコードできます。


main.dart

Map userMap = json.decode(json);

var user = User.fromJson(userMap);

エンコード・デコードのロジックをコードジェネレーターに移譲することで、'name''email'を書く必要がなくなりました。


補足

JSONのキーと別名でモデルクラスのメンバ変数を定義した場合(例えばキーがsnake_caseでメンバ変数名をlowerCaseにしたい場合)はJsonKeyアノテーションをつけることでJSONのキー名を指定できます。

@JsonKey(name: 'first_name')

final int firstName;

以下のコマンドをFlutterプロジェクトのRootで実行することで、変更を検知してコード生成を自動化することもできます。

flutter packages pub run build_runner watch


参考