DevToolBoxฟรี
บล็อก

JSON เป็น Dart: คู่มือ Model Class สำหรับ Flutter

10 นาทีในการอ่านโดย DevToolBox

Converting JSON to Dart model classes is one of the most common tasks in Flutter development. Whether you're fetching data from a REST API or reading local configuration, you need well-structured Dart classes to safely parse and use your JSON data.

Why You Need Model Classes

  • Type safety — catch errors at compile time instead of runtime
  • IDE autocompletion and refactoring support
  • Clear data contracts between frontend and backend
  • Easier testing and maintenance

Basic JSON to Dart Type Mapping

JSON TypeDart TypeExample
stringString"hello" → "hello"
number (int)int42 → 42
number (float)double3.14 → 3.14
booleanbooltrue → true
nullNull / dynamicnull → null
arrayList<T>[1,2,3] → [1,2,3]
objectMap / Class{} → User()

Manual Model Class (fromJson / toJson)

The most straightforward approach is writing model classes by hand. Here's a complete example:

// JSON input
{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com",
  "isActive": true,
  "score": 95.5
}

// Dart model class
class User {
  final int id;
  final String name;
  final String email;
  final bool isActive;
  final double score;

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

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      email: json['email'] as String,
      isActive: json['isActive'] as bool,
      score: (json['score'] as num).toDouble(),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
      'isActive': isActive,
      'score': score,
    };
  }
}

Handling Nested Objects

When your JSON contains nested objects, create separate Dart classes for each level:

// JSON with nested object
{
  "id": 1,
  "name": "John",
  "address": {
    "street": "123 Main St",
    "city": "Springfield",
    "zipCode": "62701"
  }
}

// Dart classes
class Address {
  final String street;
  final String city;
  final String zipCode;

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

  factory Address.fromJson(Map<String, dynamic> json) {
    return Address(
      street: json['street'] as String,
      city: json['city'] as String,
      zipCode: json['zipCode'] as String,
    );
  }

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

class User {
  final int id;
  final String name;
  final Address address;

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

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      address: Address.fromJson(json['address'] as Map<String, dynamic>),
    );
  }

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

Handling Lists and Arrays

JSON arrays map to Dart List types. Handle both simple and complex arrays:

// JSON with arrays
{
  "name": "John",
  "hobbies": ["coding", "reading", "gaming"],
  "orders": [
    {"id": 1, "product": "Laptop", "price": 999.99},
    {"id": 2, "product": "Mouse", "price": 29.99}
  ]
}

// Dart
class User {
  final String name;
  final List<String> hobbies;
  final List<Order> orders;

  User({required this.name, required this.hobbies, required this.orders});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'] as String,
      hobbies: List<String>.from(json['hobbies'] as List),
      orders: (json['orders'] as List)
          .map((e) => Order.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }
}

Null Safety Best Practices

With Dart's sound null safety, you need to handle nullable fields properly:

  • Use `required` keyword for fields that must always be present
  • Use `?` suffix for nullable types (e.g., `String?`)
  • Provide default values with `??` operator in fromJson
  • Use `late` keyword only when you're certain the value will be initialized
class User {
  final int id;
  final String name;
  final String? bio;        // nullable
  final String avatarUrl;   // with default

  User({
    required this.id,
    required this.name,
    this.bio,
    this.avatarUrl = 'https://example.com/default-avatar.png',
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      bio: json['bio'] as String?,
      avatarUrl: json['avatarUrl'] as String? ?? 'https://example.com/default-avatar.png',
    );
  }
}

Using json_serializable Package

For larger projects, the json_serializable package automates the boilerplate:

Step 1: Add Dependencies

# pubspec.yaml
dependencies:
  json_annotation: ^4.8.1

dev_dependencies:
  json_serializable: ^6.7.1
  build_runner: ^2.4.6

Step 2: Create Model with Annotations

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final int id;
  final String name;
  final String email;

  @JsonKey(name: 'is_active')
  final bool isActive;

  @JsonKey(defaultValue: 0.0)
  final double score;

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

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

Step 3: Run Build Runner

dart run build_runner build --delete-conflicting-outputs

Using Freezed for Immutable Models

The freezed package generates immutable classes with copyWith, equality, and JSON serialization:

import 'package:freezed_annotation/freezed_annotation.dart';

part 'user.freezed.dart';
part 'user.g.dart';

@freezed
class User with _$User {
  const factory User({
    required int id,
    required String name,
    required String email,
    @Default(false) bool isActive,
  }) = _User;

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

Common Mistakes and Fixes

MistakeFix
Using `json['key']` without null checkUse `json['key'] as String? ?? ''` or handle null
Forgetting to convert nested objectsCall `NestedClass.fromJson(json['key'])` for objects
Using `int` for all numbersUse `num` and convert: `(json['price'] as num).toDouble()`
Not handling missing keysUse `json.containsKey('key')` or provide defaults
Returning wrong type in toJsonEnsure nested objects call their own `.toJson()`

FAQ

What is the best way to convert JSON to Dart classes?

For small projects, manual conversion works well. For larger projects, use json_serializable or freezed packages to auto-generate the boilerplate code. Online tools like our JSON to Dart Converter can help generate the initial code.

How do I handle dynamic JSON keys in Dart?

Use Map<String, dynamic> for objects with unknown keys. For example: final Map<String, dynamic> metadata = json['metadata'] as Map<String, dynamic>;

Should I use json_serializable or freezed?

Use json_serializable for simple JSON serialization needs. Use freezed when you also want immutability, copyWith, union types, and sealed classes. Freezed internally uses json_serializable for JSON support.

How do I handle dates in JSON to Dart conversion?

JSON doesn't have a native date type. Parse ISO 8601 strings with DateTime.parse(json['date']). In toJson, use dateTime.toIso8601String(). With json_serializable, use @JsonKey(fromJson: DateTime.parse, toJson: _dateToString).

𝕏 Twitterin LinkedIn
บทความนี้มีประโยชน์ไหม?

อัปเดตข่าวสาร

รับเคล็ดลับการพัฒนาและเครื่องมือใหม่ทุกสัปดาห์

ไม่มีสแปม ยกเลิกได้ตลอดเวลา

ลองเครื่องมือที่เกี่ยวข้อง

DTJSON to Dart{ }JSON FormatterKTJSON to KotlinTSJSON to TypeScript

บทความที่เกี่ยวข้อง

ไวยากรณ์ YAML & การตรวจสอบ: ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

เชี่ยวชาญไวยากรณ์ YAML: กฎการย่อหน้า ข้อผิดพลาดการ parse ชนิดข้อมูล และแนวปฏิบัติที่ดี

JSON เป็น Kotlin Data Class: คู่มือ kotlinx.serialization, Moshi และ Gson

แปลง JSON เป็น data class Kotlin ออนไลน์ เรียนรู้การแยกวิเคราะห์ JSON ด้วย kotlinx.serialization, Moshi และ Gson