Home > Back-end >  How to map array of object returning from api in Flutter?
How to map array of object returning from api in Flutter?

Time:05-09

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

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,
    };

CodePudding user response:

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,
    );
  }

CodePudding user response:

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));
     });

CodePudding user response:

have you imported JSON file in pubspec.yaml

  • Related