adplus-dvertising

How to map array of object returning from api in Flutter?

Asked 7 months ago
Viewed 1.16 k times

I have following REST api endpoint I need to consume from Flutter application. I have fromJson, toJson model mapping as usual. How can I map these in to array.

[
  {
    "id": 1,
    "userId": 0,
    "type": "Create",
    "tableName": "Province",
    "dateTime": "2022-03-14T03:23:41.338932",
    "oldValues": null,
    "newValues": "{\"NameEN\":\"Banteay Meanchey\",\"NameKH\":\"\\u1794\\u1793\\u17D2\\u1791\\u17B6\\u1799\\u1798\\u17B6\\u1793\\u1787\\u17D0\\u1799\",\"Type\":\"\\u1781\\u17C1\\u178F\\u17D2\\u178F\"}",
    "affectedColumns": null,
    "primaryKey": "{\"Code\":1}"
  },
  {
    "id": 2,
    "userId": 0,
    "type": "Create",
    "tableName": "Province",
    "dateTime": "2022-03-14T03:23:41.351456",
    "oldValues": null,
    "newValues": "{\"NameEN\":\"Battambang\",\"NameKH\":\"\\u1794\\u17B6\\u178F\\u17CB\\u178A\\u17C6\\u1794\\u1784\",\"Type\":\"\\u1781\\u17C1\\u178F\\u17D2\\u178F\"}",
    "affectedColumns": null,
    "primaryKey": "{\"Code\":2}"
  }
]

I try to have following code but it doesnot work. One way is to return {} json object instead of [] array of object. But I do not want to change how API return the json.

Future<List<Audit>> getAudits() async {
    final jsonString = await dio.get('auditlogs');
    final List decodedJson = json.decode(jsonString.data.toString());
    final List<Audit> audits = decodedJson.map((e) => Audit.fromJson(e)).toList();
    return audits;
  }

Update additional context I print the jsonString after

final jsonString = await dio.get('auditlogs');

Here below is the result. what wrong with this json.

[{id: 1, userId: 0, type: Create, tableName: Province, dateTime:
2022-03-14T03:23:41.338932, oldValues: null, newValues:
{"NameEN":"Banteay
Meanchey","NameKH":"\u1794\u1793\u17D2\u1791\u17B6\u1799\u1798\u17B6\u1
793\u1787\u17D0\u1799","Type":"\u1781\u17C1\u178F\u17D2\u178F"},
affectedColumns: null, primaryKey: {"Code":1}}, {id: 2, userId: 0,
type: Create, tableName: Province, dateTime:
2022-03-14T03:23:41.351456, oldValues: null, newValues:
{"NameEN":"Battambang","NameKH":"\u1794\u17B6\u178F\u17CB\u178A\u17C6\u
1794\u1784","Type":"\u1781\u17C1\u178F\u17D2\u178F"}, affectedColumns:
null, primaryKey: {"Code":2}}, {id: 3, userId: 0, type: Create,
tableName: Province, dateTime: 2022-03-14T03:23:41.351487, oldValues:
null, newValues: {"NameEN":"Kampong
Cham","NameKH":"\u1780\u17C6\u1796\u1784\u17CB\u1785\u17B6\u1798","Type
":"\u1781\u17C1\u178F\u17D2\u178F"}, affectedColumns: null, primaryKey:
{"Code":3}}, {id: 4, userId: 0, type: Create, tableName: Province,
dateTime: 2022-03-14T03:23:41.351503, oldValues: null, newValues:
{"NameEN":"Kampong
Chhnang","NameKH":"\u1780\u17C6\u1796\u1784\u17CB\u1786\u17D2\u1793\u17
B6\u17C6\u1784","Type":"\u1781\u17C1\u178F\u17D2\u178F"},
affectedColumns: null, primaryKey: {"Code":4}}, {id: 5, userId: 0,
type: Create, tableName: Province, dateTime:
2022-03-14T03:23:41.351515, oldValues: null, newValues:
{"NameEN":"Kampong
Speu","NameKH":"\u178F\u1780\u17C6\u1796\u1784\u17CB\u179F\u17D2\u1796\
u17BA","Type":"\u1781\u17C1\u178F\u17D2\u178F"}, affectedColumns: null,
primaryKey: {"Code":5}}, {id: 6, userId: 0, type: Create, tableName:
Province, dateTime: 2022-03-14T03:23:41.351528, oldValues: null,
newValues: {"NameEN":"Kampong
Thom","NameKH":"\u1780\u17C6\u1796\u1784\u17CB\u1792\u17C6","Type":"\u1
781\u17C1\u178F\u17D2\u178F"}, affectedColumns: null, primaryKey:
{"Code":6}}]

Data Model

    import 'package:json_annotation/json_annotation.dart';

part 'audit.g.dart';

@JsonSerializable()
class Audit {
  int id;
  int userId;
  String? type;
  String? tableName;
  DateTime dateTime;
  String? oldValues;
  String? newValues;
  String? affectedColumns;
  String? primaryKey;

  Audit(
    this.id,
    this.userId,
    this.type,
    this.tableName,
    this.dateTime,
    this.oldValues,
    this.newValues,
    this.affectedColumns,
    this.primaryKey,
  );

  factory Audit.fromJson(Map<String, dynamic> json) => _$AuditFromJson(json);

  Map<String, dynamic> toJson() => _$AuditToJson(this);
}

Generated JSON Serialization

// GENERATED CODE - DO NOT MODIFY BY HAND

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'audit.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Audit _$AuditFromJson(Map<String, dynamic> json) => Audit(
      json['id'] as int,
      json['userId'] as int,
      json['type'] as String?,
      json['tableName'] as String?,
      DateTime.parse(json['dateTime'] as String),
      json['oldValues'] as String?,
      json['newValues'] as String?,
      json['affectedColumns'] as String?,
      json['primaryKey'] as String?,
    );

Map<String, dynamic> _$AuditToJson(Audit instance) => <String, dynamic>{
      'id': instance.id,
      'userId': instance.userId,
      'type': instance.type,
      'tableName': instance.tableName,
      'dateTime': instance.dateTime.toIso8601String(),
      'oldValues': instance.oldValues,
      'newValues': instance.newValues,
      'affectedColumns': instance.affectedColumns,
      'primaryKey': instance.primaryKey,
    };

asked 7 months ago

Correct Answer

Try this:

 Future<List<Audit>> getAudits() async {
   var response = await dio.get('auditlogs');

   List<Audit> result = [];

  (jsonDecode(response.bodyString)).forEach((element) {
       result.add(Audit.fromJson(element));
     });

  return result; 
}
  • Update:

Try this:

(jsonDecode(response.data.toString())).forEach((element) {
       result.add(Audit.fromJson(element));
     });

Or this:

(jsonDecode(response.data)).forEach((element) {
       result.add(Audit.fromJson(element));
     });
answered 7 months ago

Other Answer

The problem is there is null value in your JSON but you didn't check for null. Modify the generated code to check for null values before decoding.

I've test it and it worked like charm:

  factory Audit.fromJson(Map<String, dynamic> json) {
    return Audit(
      json['id'] as int,
      json['userId'] as int,
      json['type'] as String,
      json['tableName'] as String,
      DateTime.parse(json['dateTime'] as String),
      (json['oldValues'] != null) ? json['oldValues'] as String : '',
      json['newValues'] as String,
      (json['affectedColumns'] != null)
          ? json['affectedColumns'] as String
          : '',
      json['primaryKey'] as String,
    );
  }

Yet better solution:

Modify your Audit class to support null value such as String?

class Audit {
  int id;
  int userId;
  String type;
  String tableName;
  DateTime dateTime;
  String? oldValues;
  String newValues;
  String? affectedColumns;
  String primaryKey;

  Audit(
    this.id,
    this.userId,
    this.type,
    this.tableName,
    this.dateTime,
    this.oldValues,
    this.newValues,
    this.affectedColumns,
    this.primaryKey,
  );
}

and refactor Audit.fromJson() to reflect the changes in the class:

  factory Audit.fromJson(Map<String, dynamic> json) {
    return Audit(
      json['id'] as int,
      json['userId'] as int,
      json['type'] as String,
      json['tableName'] as String,
      DateTime.parse(json['dateTime'] as String),
      json['oldValues'] as String?,
      json['newValues'] as String,
      json['affectedColumns'] as String?,
      json['primaryKey'] as String,
    );
  }
answered 7 months ago