flutter-implement-json-serialization について
Flutter 開発者向けに、モデル変換からネットワーク応答の解析、大きなデータのバックグラウンド処理までを扱う手動 JSON シリアライズのスキルです。
主な機能
- 01モデルの fromJson と toJson の実装
- 02デコードした JSON の型変換
- 03compute による isolate 解析
- 04HTTP ステータス確認とエラー処理
- 05シリアライズ処理のユニットテスト
活用シーン
- 01Dart モデルへの JSON 変換追加
- 02HTTP リクエストの応答データ解析
- 03大きな JSON ドキュメントのバックグラウンド処理
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ flutter/ agent-plugins --skill flutter-implement-json-serializationインストール後、Claude Code で/flutter-implement-json-serializationを入力して読み込まれたか確認します。
詳細
Flutter での手動 JSON シリアライズ
目次
基本ガイドライン
dart:convertをインポートする:手動で JSON をエンコード(jsonEncode)およびデコード(jsonDecode)するには、Flutter に組み込まれているdart:convertライブラリを使用します。- 型安全性を徹底する:
jsonDecode()のdynamicな戻り値は、必ず想定される型にキャストします。通常、オブジェクトにはMap<String, dynamic>、配列にはList<dynamic>を使用します。 - シリアライズロジックをカプセル化する:JSON 構造に対応するプロパティを持つプレーンなモデルクラスを定義します。モデル内に
fromJsonファクトリーコンストラクターとtoJsonメソッドを実装します。 - バックグラウンドで解析する:大きな JSON ドキュメントを解析する場合(実行時間が 16ms を超える場合)、UI のカクつきを防ぐため、Flutter の
compute()関数を使って解析ロジックを別の isolate に移します。 - 失敗時に例外をスローする:HTTP レスポンスを処理する際、ステータスコードが成功を示していない場合(例:200 OK または 201 Created ではない場合)は、例外をスローします。
nullは返さないでください。
ワークフロー:シリアライズ可能なモデルの実装
このチェックリストに従って、データモデルの手動 JSON シリアライズを実装します。
タスクの進捗:
-
finalプロパティを持つプレーンなモデルクラスを定義します。 -
factory Model.fromJson(Map<String, dynamic> json)コンストラクターを実装します。 -
Map<String, dynamic> toJson()メソッドを実装します。 - 両方のシリアライズメソッドのユニットテストを作成します。
- バリデーターを実行 -> 型の不一致エラーを確認 -> キャストロジックを修正します。
- モデルを定義する:JSON キーに対応するプロパティを持つクラスを作成します。
fromJsonを実装する:Mapから値を取り出し、適切な Dart 型にキャストします。パターンマッチングまたは明示的なキャストを使用します。toJsonを実装する:クラスのプロパティを対応する JSON 文字列キーにマッピングしたMap<String, dynamic>を返します。- 検証する:ユニットテストを実行し、型安全性、自動補完、コンパイル時の例外処理が正しく機能することを確認します。
ワークフロー:JSON の取得と解析
ネットワークリクエストから JSON を取得して解析する際は、この条件付きワークフローを使用します。
タスクの進捗:
- HTTP リクエストを実行します。
- レスポンスのステータスコードを検証します。
- 解析方法(同期または isolate)を決定します。
- JSON をデコードし、モデルにマッピングします。
- リクエストを実行する:
httpパッケージを使用してネットワーク呼び出しを行います。 - レスポンスを検証する:
response.statusCode == 200(または POST の場合は 201)なら、解析に進みます。- ステータスコードが失敗を示す場合は、
Exceptionをスローします。
- 解析方法を決定する:
- 小さなペイロード(例:単一のオブジェクト)を解析する場合は、メインスレッドで同期的に解析します。
- 大きなペイロード(例:数千個のオブジェクトを含む配列)を解析する場合は、
compute(parseFunction, response.body)を使用し、バックグラウンドの isolate で解析します。
- デコードしてマッピングする:デコードした JSON をモデルの
fromJsonコンストラクターに渡します。
例
高精度なモデルの実装
import 'dart:convert';
class User {
final int id;
final String name;
final String email;
const User({
required this.id,
required this.name,
required this.email,
});
// Factory constructor for deserialization
factory User.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
'id': int id,
'name': String name,
'email': String email,
} =>
User(
id: id,
name: name,
email: email,
),
_ => throw const FormatException('Failed to load User.'),
};
}
// Method for serialization
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}
同期解析(小さなペイロード)
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<User> fetchUser(http.Client client, int userId) async {
final response = await client.get(
Uri.parse('https://api.example.com/users/$userId'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Decode returns dynamic, cast to Map<String, dynamic>
final Map<String, dynamic> jsonMap = jsonDecode(response.body) as Map<String, dynamic>;
return User.fromJson(jsonMap);
} else {
throw Exception('Failed to load user');
}
}
バックグラウンド解析(大きなペイロード)
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// Top-level function required for compute()
List<User> parseUsers(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<dynamic>).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
Future<List<User>> fetchUsers(http.Client client) async {
final response = await client.get(
Uri.parse('https://api.example.com/users'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Offload expensive parsing to a background isolate
return compute(parseUsers, response.body);
} else {
throw Exception('Failed to load users');
}
}
コメント
Markdown 対応