JSON to Dart

JSONからfromJsonとtoJson付きのDartクラスを自動生成

サンプルを試す
ルートクラス名:

JSON入力

Dart出力

ローカルで実行 · シークレットの貼り付けも安全
Dartクラスがここに表示されます…

JSONからDartへの変換とは?

JSONからDartへの変換は、生のJSONオブジェクトから型付きフィールド・名前付きコンストラクター・fromJsonファクトリー・toJsonメソッドを持つDartクラス定義を生成するプロセスです。FlutterではDartのランタイムリフレクション(dart:mirrors)が無効化されているため、明示的なマッピングコードなしにJSONを型付きオブジェクトへ逆シリアル化することはできません。REST APIのレスポンス・Firebaseドキュメント・設定ペイロードのいずれも、フィールドにタイプセーフにアクセスするには対応するDartモデルクラスが必要です。

JSON用の標準的なDartモデルクラスは、各キーに対するfinalフィールド・名前付きパラメーターを持つコンストラクター(null非許容フィールドにはrequiredキーワードを使用)・Map<String, dynamic>から読み取るfromJsonファクトリーコンストラクター・Map<String, dynamic>を返すtoJsonメソッドを宣言します。ネストされたJSONオブジェクトは別々のクラスになります。配列は型付きListフィールドになります。null許容のJSON値はDartのnullセーフ構文として型に?サフィックスが付きます。

これらのモデルクラスを手書きするには、各JSONキーを読み取り・Dartの型を決定し・各フィールドのfromJsonキャスト(.map().toList()を使ったリストマッピングを含む)を作成し・toJsonのマップリテラルを構築し・ネストされたオブジェクトごとに繰り返す必要があります。フィールドが12個・ネストされたオブジェクトが2つあるJSONオブジェクトなら、3つのクラス・6行のファクトリー・数十のキャスト式が必要です。変換ツールはこれをすべて1回のペーストからミリ秒で生成します。

JSONからDart変換ツールを使う理由

DartモデルクラスをJSONから手動で作成するには、フィールド名の確認・サンプル値からの型推測・正確なnull処理を含むfromJsonキャストの記述を、ネストされたオブジェクトごとに繰り返す必要があります。APIの仕様が変わると、コンストラクター・fromJson・toJsonのすべてを手作業で更新しなければなりません。変換ツールはその機械的な作業を排除します。

即座にクラスを生成
JSONを貼り付けるだけで、1秒以内にコンストラクター・fromJsonファクトリー・toJsonメソッド付きの完全なDartクラスが得られます。ネストされたオブジェクトとリストは自動的に検出してマッピングされます。
🔒
プライバシーファーストな処理
変換はすべてブラウザ上でJavaScriptを使って実行されます。JSONデータがマシンの外に出ることはありません。APIキー・トークン・本番ペイロードはプライベートのままです。
📝
nullセーフな出力
生成されるクラスはDartのサウンドnullセーフティを使用します。null許容のJSONフィールドには?型サフィックスが付き、コンストラクターでrequiredキーワードが省略されます。null非許容フィールドにはrequiredが付きます。
📦
インストール・サインアップ不要
ページを開いてJSONを貼り付けるだけです。Dart SDKもpubの依存関係もアカウントも不要です。ブラウザがあればどのデバイスでも動作します。

JSONからDart変換のユースケース

Flutterアプリ開発
httpやdioパッケージで利用するREST APIレスポンスのモデルクラスを生成します。バックエンドが返すJSONを貼り付けて、jsonDecodeとウィジェットのレンダリングに対応したDartクラスをすぐに取得できます。
Firebase / Firestoreとの統合
Firestoreのドキュメントスナップショット用に型付きモデルクラスを作成します。サンプルドキュメントをJSONとして貼り付けてDartクラスを生成し、リポジトリレイヤーでsnapshot.data()とともにfromJsonを使用します。
状態管理モデル
Riverpod・Bloc・Provider用の型付き状態オブジェクトを定義します。期待する状態の形状をJSONとして貼り付け、状態の永続化とハイドレーション用のtoJson付きイミュータブルなDartクラスを取得できます。
APIクライアントのコード生成
RetrofitまたはChopperのAPIクライアント用リクエスト・レスポンスモデルを生成します。サンプルのJSONペイロードを貼り付けて、OpenAPIのレスポンススキーマに合致したDartクラスを取得できます。
自動テスト
実際のAPIレスポンスから型付きテストフィクスチャを構築します。JSONサンプルを貼り付けてモデルクラスを生成し、フィクスチャ構造を手書きすることなくユニットテストとウィジェットテストで直接使用できます。
Dartパターンの学習
Flutterを学習している方は任意のJSON構造を貼り付けて、Dartがどのように表現するかを確認できます:finalフィールド・名前付きコンストラクター・fromJsonのファクトリーパターン・nullセーフティアノテーションを実践で理解できます。

JSONからDartへの型マッピング

すべてのJSON値は特定のDart型にマッピングされます。下表は変換ツールが各JSON型をどのように変換するかを示しています。「代替」列には、使用頻度が低い場面や手動マッピングで使われる型が示されています。

JSON型値の例Dart型代替
string"hello"StringString
number (integer)42intint
number (float)3.14doubledouble
booleantrueboolbool
nullnulldynamicNull / dynamic
object{"k": "v"}NestedClassMap<String, dynamic>
array of strings["a", "b"]List<String>List<String>
array of objects[{"id": 1}]List<Item>List<Item>
mixed array[1, "a"]List<dynamic>List<dynamic>

DartのJSONシリアル化アプローチ

DartとFlutterにはJSONシリアル化を扱う複数の方法があります。手動のfromJson/toJsonは最もシンプルなアプローチでコード生成が不要です。大規模プロジェクトでは、json_serializableやfreezedなどbuild_runnerベースのソリューションがコンパイル時にボイラープレートを生成し、エラーを削減してモデルをJSONコントラクトと整合させます。

アプローチ説明ソース
json_serializableCode-generation-based JSON serialization. Generates .g.dart files at build time via build_runner. Type-safe and compile-time verified.Official (Google)
freezedGenerates immutable data classes with copyWith, fromJson/toJson, equality, and pattern matching support. Built on top of json_serializable.Community (rrousselGit)
built_valueGenerates immutable value types with serialization. Enforces immutability patterns. Used in larger codebases with strict data modeling.Google
dart_mappableAnnotation-based mapper that generates fromJson, toJson, copyWith, and equality. Simpler setup than freezed with similar features.Community
Manual fromJson/toJsonHand-written factory constructors and toJson methods. No code generation needed. Full control over the mapping logic.Built-in Dart

手動 vs json_serializable vs freezed

DartにはJSONモデルクラスを扱う一般的なアプローチが3つあります。手動のfromJson/toJsonは依存関係ゼロです。json_serializableはマッピングコードを自動生成します。freezedはjson_serializableの上にイミュータビリティ・copyWith・パターンマッチングを追加します。

Manual fromJson/toJson
fromJsonファクトリーとtoJsonメソッドを手書きします。依存関係ゼロ・build_runnerのステップ不要です。キャストロジックとエラー処理を完全に制御できます。モデルが少ない小規模プロジェクト、またはコードジェネレーターでは表現できないカスタム逆シリアル化が必要な場合に最適です。このツールが生成する出力形式です。
json_serializable
クラスに@JsonSerializable()アノテーションを付与してdart run build_runner buildを実行します。ジェネレーターが_$ClassFromJsonと_$ClassToJson関数を含む.g.dartファイルを生成します。フィールドのリネーム・デフォルト値・カスタムコンバーター用の@JsonKeyに対応しています。中〜大規模のFlutterプロジェクトにおける標準的な選択肢です。
freezed
@freezedアノテーションを付与すると、fromJson・toJson・copyWith・等値演算(==とhashCode)・toStringが自動生成されるイミュータブルなクラスが得られます。シールドクラスパターン用のunion型もサポートしています。freezedとjson_serializableの両方をdev依存関係として追加する必要があります。状態管理モデルと複雑なドメインオブジェクトに最適です。

コード例

以下の例は、生成されたDartクラスをJSON逆シリアル化に使用する方法、build_runnerでjson_serializableをセットアップする方法、そしてJavaScriptとPythonからプログラムでDartクラスを生成する方法を示しています。

Dart (manual fromJson / toJson)
import 'dart:convert';

class User {
  final int id;
  final String name;
  final String email;
  final bool active;
  final Address address;
  final List<String> tags;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.active,
    required this.address,
    required this.tags,
  });

  factory User.fromJson(Map<String, dynamic> json) => User(
    id: json['id'] as int,
    name: json['name'] as String,
    email: json['email'] as String,
    active: json['active'] as bool,
    address: Address.fromJson(json['address'] as Map<String, dynamic>),
    tags: (json['tags'] as List<dynamic>).map((e) => e as String).toList(),
  );

  Map<String, dynamic> toJson() => {
    'id': id,
    'name': name,
    'email': email,
    'active': active,
    'address': address.toJson(),
    'tags': tags,
  };
}

class Address {
  final String street;
  final String city;
  final String zip;

  Address({required this.street, required this.city, required this.zip});

  factory Address.fromJson(Map<String, dynamic> json) => Address(
    street: json['street'] as String,
    city: json['city'] as String,
    zip: json['zip'] as String,
  );

  Map<String, dynamic> toJson() => {'street': street, 'city': city, 'zip': zip};
}

void main() {
  final jsonStr = '{"id":1,"name":"Alice","email":"alice@example.com","active":true,"address":{"street":"123 Main","city":"Springfield","zip":"12345"},"tags":["admin","user"]}';
  final user = User.fromJson(jsonDecode(jsonStr));
  print(user.name); // -> Alice
  print(jsonEncode(user.toJson())); // -> round-trip back to JSON
}
Dart (json_serializable + build_runner)
// pubspec.yaml dependencies:
//   json_annotation: ^4.8.0
//   dev_dependencies:
//     build_runner: ^2.4.0
//     json_serializable: ^6.7.0

import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart'; // generated by: dart run build_runner build

@JsonSerializable()
class User {
  final int id;
  final String name;
  final String email;
  @JsonKey(name: 'is_active')
  final bool isActive;
  final List<String> tags;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.isActive,
    required this.tags,
  });

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

// Run code generation:
// dart run build_runner build --delete-conflicting-outputs
JavaScript (generate Dart classes from JSON)
function jsonToDart(obj, name = "Root") {
  const classes = [];
  function infer(val, fieldName) {
    if (val === null) return "dynamic";
    if (typeof val === "string") return "String";
    if (typeof val === "number") return Number.isInteger(val) ? "int" : "double";
    if (typeof val === "boolean") return "bool";
    if (Array.isArray(val)) {
      const first = val.find(v => v !== null);
      if (!first) return "List<dynamic>";
      return `List<${infer(first, fieldName)}>`;
    }
    if (typeof val === "object") {
      const cls = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
      build(val, cls);
      return cls;
    }
    return "dynamic";
  }
  function build(obj, cls) {
    const fields = Object.entries(obj).map(([k, v]) =>
      `  final ${infer(v, k)} ${k};`
    );
    classes.push(`class ${cls} {\n${fields.join("\n")}\n}`);
  }
  build(obj, name);
  return classes.join("\n\n");
}

console.log(jsonToDart({ id: 1, name: "Alice", scores: [98, 85] }, "User"));
// class User {
//   final int id;
//   final String name;
//   final List<int> scores;
// }
Python (generate Dart model from JSON)
import json

def json_to_dart(obj: dict, class_name: str = "Root") -> str:
    classes = []

    def infer(val, name):
        if val is None:
            return "dynamic"
        if isinstance(val, bool):
            return "bool"
        if isinstance(val, int):
            return "int"
        if isinstance(val, float):
            return "double"
        if isinstance(val, str):
            return "String"
        if isinstance(val, list):
            if not val:
                return "List<dynamic>"
            return f"List<{infer(val[0], name)}>"
        if isinstance(val, dict):
            cls = name[0].upper() + name[1:]
            build(val, cls)
            return cls
        return "dynamic"

    def build(obj, cls):
        fields = [f"  final {infer(v, k)} {k};" for k, v in obj.items()]
        classes.append(f"class {cls} {{\n" + "\n".join(fields) + "\n}")

    build(obj, class_name)
    return "\n\n".join(classes)

data = json.loads('{"id": 1, "name": "Alice", "active": true}')
print(json_to_dart(data, "User"))
# class User {
#   final int id;
#   final String name;
#   final bool active;
# }

よくある質問

FlutterがJSONの逆シリアル化にdart:mirrorsを使えない理由は何ですか?
Flutterはdart:mirrors(リフレクションライブラリ)を無効化しています。これはツリーシェイキングがコンパイル時にどのコードが使用されるかを把握する必要があるためです。リフレクションがあるとコンパイラーが未使用のクラスを除去できず、アプリサイズが増大します。そのためFlutterプロジェクトでは、ランタイムリフレクションの代わりに明示的なfromJson/toJsonメソッドまたはコード生成が必要です。
json_serializableを使うべきか、fromJsonを手書きすべきか?
モデルクラスが10個未満のプロジェクトでは、手書きのfromJson/toJsonはシンプルでビルド依存関係も増えません。モデルが10個を超える場合、または頻繁に変更されるモデルがある場合は、json_serializableが時間を節約してコピーペーストのミスを削減します。アノテーションからマッピングコードを生成するため、フィールドの追加はbuild_runnerの再実行だけで対応できます。
変換ツールはネストされたJSONオブジェクトをどのように処理しますか?
ネストされたJSONオブジェクトはそれぞれ別のDartクラスになります。"address"というJSONフィールドが"street"と"city"キーを持つオブジェクトを含む場合、変換ツールはそれらのフィールドを持つAddressクラスを作成し、親フィールドの型をAddressとします。fromJsonファクトリーはネストされたマップをキャストしてAddress.fromJsonに渡します。
JSONフィールドがnullの場合はどうなりますか?
nullフィールドはnull値だけでは意図する型を判定できないため、?サフィックス付きのdynamic型となります。APIコントラクトから型がわかったら、dynamic?を正しい型(String?、int?など)に置き換えてください。Dartのnullセーフティがコンパイルタイムでnullチェックを適切に強制します。
有効なDart識別子でないJSONキーはどう扱いますか?
"first-name"や"2nd_place"のようなJSONキーは有効なDartフィールド名ではありません。手動のfromJsonではファクトリーコンストラクター内で任意のJSONキーを任意のDartフィールド名にマッピングできます。json_serializableでは@JsonKey(name: 'first-name')アノテーションでフィールドを指定します。変換ツールはキー名を自動的にcamelCaseのDartフィールドに変換します。
このツールの出力をfreezedで使えますか?
このツールは手動のfromJson/toJson付きの標準Dartクラスを生成します。freezedに変換するには、クラスを@freezedアノテーション付きに変更し、手書きのコンストラクターとファクトリーを削除してfreezedミックスインを追加します。その後build_runnerを実行して.freezed.dartと.g.dartファイルを生成します。生成された出力のフィールド名と型はそのまま引き継がれます。
生のマップと型付きDartクラスのJSONの違いは何ですか?
生のマップ(Map<String, dynamic>)はJSONデータに型チェックなしで直接アクセスできます。呼び出し側ですべての値をキャストする必要があり、キー名のタイポはランタイムで検出されません。型付きDartクラスはfromJsonの境界で型の不一致を検出し、フィールド名のIDEオートコンプリートを提供し、リファクタリングを安全にします。パフォーマンスの差はほぼなく、メリットは完全に正確性と保守性にあります。