Flutter JSON Parsing

Converting JSON data to Dart objects

📦 What is JSON Parsing?

JSON parsing converts JSON strings from APIs into Dart objects you can use in your app. Flutter provides built-in tools to decode JSON and map it to custom classes.


import 'dart:convert';

// JSON string
String jsonString = '{"name": "John", "age": 25}';

// Parse to Map
Map<String, dynamic> user = json.decode(jsonString);
print(user['name']); // John
                                    

Output:

John

JSON Parsing Methods

🔄

json.decode()

Convert JSON string to Map

Map data = json.decode(
  '{"id": 1, "name": "Alice"}'
);
📝

json.encode()

Convert Map to JSON string

String jsonStr = json.encode({
  'id': 1, 
  'name': 'Alice'
});
🏗️

Model Classes

Create custom Dart classes

class User {
  final int id;
  final String name;
  
  User.fromJson(Map json);
}
⚙️

Code Generation

Auto-generate parsing code

@JsonSerializable()
class User {
  final String name;
}

🔹 Basic JSON Parsing

Parse simple JSON objects:

import 'dart:convert';

void parseSimpleJson() {
  // JSON string
  String jsonString = '''
  {
    "name": "John Doe",
    "email": "[email protected]",
    "age": 30
  }
  ''';

  // Decode JSON
  Map<String, dynamic> user = json.decode(jsonString);

  // Access values
  print('Name: ${user['name']}');
  print('Email: ${user['email']}');
  print('Age: ${user['age']}');
}

Output:

Name: John Doe

Email: [email protected]

Age: 30

🔹 Parsing JSON Arrays

Handle lists of JSON objects:

void parseJsonArray() {
  String jsonString = '''
  [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"},
    {"id": 3, "name": "Charlie"}
  ]
  ''';

  // Decode to List
  List<dynamic> users = json.decode(jsonString);

  // Loop through users
  for (var user in users) {
    print('ID: ${user['id']}, Name: ${user['name']}');
  }
}

Output:

ID: 1, Name: Alice

ID: 2, Name: Bob

ID: 3, Name: Charlie

🔹 Creating Model Classes

Convert JSON to type-safe Dart objects:

class User {
  final int id;
  final String name;
  final String email;

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

  // Factory constructor for JSON parsing
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
    );
  }

  // Convert to JSON
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
    };
  }
}

// Usage
String jsonString = '{"id": 1, "name": "Alice", "email": "[email protected]"}';
User user = User.fromJson(json.decode(jsonString));
print(user.name); // Alice

Output:

Alice

🔹 Nested JSON Parsing

Handle complex nested structures:

class Address {
  final String street;
  final String city;

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

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

class User {
  final String name;
  final Address address;

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

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

// Parse nested JSON
String jsonString = '''
{
  "name": "John",
  "address": {
    "street": "123 Main St",
    "city": "New York"
  }
}
''';

User user = User.fromJson(json.decode(jsonString));
print('${user.name} lives in ${user.address.city}');

Output:

John lives in New York

🔹 Using json_serializable

Auto-generate parsing code with annotations:

# pubspec.yaml
dependencies:
  json_annotation: ^4.8.1

dev_dependencies:
  build_runner: ^2.4.6
  json_serializable: ^6.7.1
import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final int id;
  final String name;
  
  @JsonKey(name: 'email_address')
  final String email;

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

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

// Run: flutter pub run build_runner build

Benefits of json_serializable:

  • Reduces boilerplate code
  • Type-safe parsing
  • Handles complex nested objects
  • Custom field name mapping

🔹 Error Handling

Handle JSON parsing errors safely:

User? parseUser(String jsonString) {
  try {
    Map<String, dynamic> json = jsonDecode(jsonString);
    return User.fromJson(json);
  } catch (e) {
    print('Error parsing JSON: $e');
    return null;
  }
}

// Usage
String invalidJson = '{"name": "John"'; // Missing closing brace
User? user = parseUser(invalidJson);

if (user != null) {
  print('User: ${user.name}');
} else {
  print('Failed to parse user');
}

Output:

Error parsing JSON: FormatException

Failed to parse user

🧠 Test Your Knowledge

Which function converts a JSON string to a Dart Map?