Search code examples
jsonflutterserializationdeserialization

Flutter: How to optionally serialize many list of data or object of data?


I want to serialize optionally JSON data from API as a list or as an object. Here I'm kinda recreating how DjangoRestFramework serializer works in Flutter. Where you can optionally past a parameter many=True or many=False to indicate there will be a lot of data (like a list) or there will be only one piece of data (like an object). Here is what it looks like in Django

serializer = BookSerializer(queryset, many=True)

My serializer in flutter currently only can serialize JSON data lists, but doesn't have the ability to serialize a JSON data object optionally. Examples of data will be:

// Data as a list
{
    "message": "Berhasil mengambil profile User",
    "statusCode": 200,
    "data": [
        {
            "id": 1,
            "avatar": "32412"
        }
        .
        .
        .
        .
        {
            "id": 1,
            "avatar": "32412"
        }
    ]
}

// Data as an object
{
    "message": "Berhasil mengambil profile User",
    "statusCode": 200,
    "data": {
        "id": 1,
        "avatar": "32412"
    }
}

This is my current code:

class Data {
  final int? id;
  final String? avatar;

  Data({
    required this.id,
    required this.avatar,
  });

  factory Data.fromJson(Map<String, dynamic> json) {
    final id = json['id'];
    final avatar = json['avatar'];

    return Data(
      id: id,
      avatar: avatar,
    );
  }
}

class UserProfileSeralizer {
  final String? message;
  final int? statusCode;
  final dynamic data;
  bool many = true;

  UserProfileSeralizer(this.many, {this.message, this.statusCode, this.data});

  factory UserProfileSeralizer.fromJson(Map<String, dynamic> json) {
    final message = json['message'];
    final statusCode = json['statusCode'];

    final tempDataJson = json['data'];
    // Assign data as List or as Data based on many's value
    if (many) {
      final List data = List.from(tempDataJson);
    } else {
      final Data data = Data.fromJson(tempDataJson);
    }

    return UserProfileSeralizer(
      message: message,
      statusCode: statusCode,
      data: data,
    );
  }
}

I thought I can just access the variable many in the factory and assign data variable based on the value of many. So I'm kinda lost here and need help.

Best regards.


Solution

  • Try this:

    class Data {
      final int? id;
      final String? avatar;
    
      Data({
        required this.id,
        required this.avatar,
      });
    
      factory Data.fromJson(Map<String, dynamic> json) {
        if(json.containsKey('id') && json.containsKey('avatar')) {}
        return Data(
          id: json['id'],
          avatar: json['avatar'],
        );
      }
    }
    
    class UserProfileSeralizer {
      final String? message;
      final int? statusCode;
      final dynamic data;
    
      UserProfileSeralizer({this.message, this.statusCode, this.data});
    
      factory UserProfileSeralizer.fromJson(Map<String, dynamic> json) {
        if(json['data'] is List) {
          return UserProfileSeralizer(
              message: json['message'], 
              statusCode: json['statusCode'], 
              data: json['data'].map((e) => Data.fromJson(e)).toList()
          );
        } else {
          return UserProfileSeralizer(
              message: json['message'], 
              statusCode: json['statusCode'], 
              data: Data.fromJson(json['data'])
          );
        }
      }
    }
    

    Note that I removed the boolean variable many because you were using it to check whether json[data] is a list or not, which is simpler if you cut to the chase.