DevToolBoxZA DARMO
Blog

JSON do Dart: Kompletny przewodnik po klasach modeli Flutter

10 min czytaniaby 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
Czy to było pomocne?

Bądź na bieżąco

Otrzymuj cotygodniowe porady i nowe narzędzia.

Bez spamu. Zrezygnuj kiedy chcesz.

Try These Related Tools

DTJSON to Dart{ }JSON FormatterKTJSON to KotlinTSJSON to TypeScript

Related Articles

Składnia YAML i walidacja: Częste błędy i jak je naprawić

Opanuj składnię YAML: reguły wcięć, błędy parsowania, typy danych i najlepsze praktyki.

JSON na Kotlin Data Class: Przewodnik kotlinx.serialization, Moshi i Gson

Konwertuj JSON na data class Kotlin online. Naucz sie parsowania JSON z kotlinx.serialization, Moshi i Gson.