🤖
【Flutter】Dioとjson_serializableで始めるモダンHTTP通信
はじめに
FlutterでAPI通信を行うなら、機能豊富で使いやすいDioがデファクトスタンダードです。この記事では、JSONのモデル化を自動化する json_serializable と組み合わせた、クリーンで型安全な通信のベストプラクティスを解説します。
Dio単体での利用手順

まずは、最もシンプルなGETリクエストの実行方法です。
導入
flutter pub add dio
pubspec.yaml
dependencies:
dio: ^5.9.0
import
import 'package:dio/dio.dart';
Dioインスタンスの作成
Dio()インスタンスを作成します。
final dio = Dio();
GETリクエストの作成
awaitで非同期的にリクエストを実行します。
Dioは自動でJSONをデコードします
final dio = Dio();
Future<void> fetchItems() async {
final response = await dio.get('http://localhost:3000/datas');
print(response);
}
非同期処理を呼び出し
ウィジェットが画面に表示された直後に一度だけ実行する場合、initStateから呼び出します。このとき、async/awaitではなく、initStateは同期的に完了させるため、単に非同期関数を呼び出す形式をとります。
void initState() {
super.initState();
fetchItems();
}
Dio + json_serializableで型安全な通信を実現

JSONデータを安全なDartの独自のクラス型(モデル)に変換するために、コード生成ツールを組み合わせます。
導入
flutter pub add dio
flutter pub add json_annotation
flutter pub add --dev json_serializable
flutter pub add --dev build_runner
pubspec.yaml
dependencies:
dio: ^5.9.0
json_annotation: ^4.9.0
dev_dependencies:
json_serializable: ^6.11.1
build_runner: ^2.10.2
クラス(データモデルとなる型)を作成
- クラスを作成
class Data {
final int id;
final String title;
Data(this.id, this.title);
}
-
part 'data.g.dart';とクラスに@JsonSerializable()を付与
モデルクラスにアノテーションを付与し、自動生成コードを取り込む指示を記述します。
import 'package:json_annotation/json_annotation.dart';
part 'data.g.dart';
()
class Data {
final int id;
final String title;
Data(this.id, this.title);
}
- コード生成を実行
dart run build_runner watch
- JSONとの相互変換のメソッドやコンストラクタを記述
partで取り込んだ自動生成コードの機能を呼び出す
import 'package:json_annotation/json_annotation.dart';
part 'data.g.dart';
()
class Data {
final String id;
final String title;
Data(this.id, this.title);
factory Data.fromJson(Map<String, dynamic> json) => _$DataFromJson(json);
Map<String, dynamic> toJson() => _$DataToJson(this);
}
GETリクエストの作成
取得したdynamicなデータを、Data.fromJsonを使って型安全なList<Data>に変換します。
import 'package:dio/dio.dart';
import '../model/data.dart';
final dio = Dio();
Future<List<Data>> fetchItems() async {
final res = await dio.get<List>('http://localhost:3000/datas');
// List<dynamic> -> List<Data>に変換
final dataList = res.data!.map((el) {
return Data.fromJson(el);
}).toList();
return dataList;
}
非同期処理を呼び出し
void initState() {
super.initState();
fetchItems().then((dataList) => print(dataList));
}
POSTの例

POSTリクエストを作成
データを送信するPOSTリクエストでは、モデルのtoJson()メソッドを活用して、DartオブジェクトをJSON形式に変換して送信します。
import 'package:dio/dio.dart';
import '../model/data.dart';
final dio = Dio();
Future<void> postData(Data newData) async {
final res = await dio.post(
'http://localhost:3000/datas',
data: newData.toJson(),
);
print(res.data);
}
非同期処理を呼び出し
ボタンタップでの呼び出す例です。ユーザー操作をきっかけとする非同期処理は、コールバック関数にasyncを付けてawaitを使用します。
ElevatedButton(
onPressed: () async {
final newData = Data('999', 'some_title');
await postData(newData);
},
child: Text('send'),
サンプルコードの全体像を掲載

data.dart
import 'package:json_annotation/json_annotation.dart';
part 'data.g.dart';
()
class Data {
final String id;
final String title;
Data(this.id, this.title);
factory Data.fromJson(Map<String, dynamic> json) => _$DataFromJson(json);
Map<String, dynamic> toJson() => _$DataToJson(this);
}
fetch.dart
import 'package:dio/dio.dart';
import '../model/data.dart';
/// DIOインスタンス
final dio = Dio();
/// GETリクエスト
Future<List<Data>> fetchItems() async {
final res = await dio.get<List>('http://localhost:3000/datas');
// List<dynamic> -> List<Data>に変換
final dataList =
res.data!.map((el) {
return Data.fromJson(el);
}).toList();
return dataList;
}
/// POSTリクエスト
Future<void> postData(Data newData) async {
final res = await dio.post(
'http://localhost:3000/datas',
data: newData.toJson(),
);
print(res.data);
}
おわりに
これらの手順を踏むことで、Dioとjson_serializableを活用した、保守性が高くエラーの少ないFlutterアプリの開発が可能になります。
Discussion