Как отобразить динамические ответы api json в dart

#json #flutter #dart

Вопрос:

У меня есть полезная нагрузка API-ответа с динамическими данными в теле. API возвращает список объектов в data теге. Я пытаюсь сопоставить ответ с соответствующей моделью во время выполнения, однако при этом я получаю сообщение об ошибке. Как сопоставить объекты динамического ответа во время выполнения без явного создания модели ответа API для каждого из них? В идеале решение должно быть в состоянии определить целевую модель, с которой объект ответа должен быть сопоставлен во время выполнения.

Я получаю следующую ошибку с моим кодом: The argument type 'List<Map<String, dynamic>>' can't be assigned to the parameter type 'Map<String, dynamic>'.

После моей попытки:

 return ApiResponse<Team>.fromJson(json.decode(response.body), (data) => Team.fromJson(data) as List<Map<String, dynamic>>);
 
 // Maps the API response to object
class ApiResponse<T> {
  int status;
  String? message;
  T data;

  ApiResponse({
    required this.status,
    this.message,
    required this.data,
  });

  factory ApiResponse.fromJson(Map<String, dynamic> json, Function(List<Map<String, dynamic>>) create) {
    return ApiResponse<T>(
      status: json['status'],
      message: json['message'],
      data: create(json['data']),
    );
  }
}
 

Мои модели

 
class User{
  int? id;
  String? name;
  String? description;
  DateTime? createdAt;
  DateTime? updatedAt;

  User({
    this.id,
    this.name,
    this.description,
    this.createdAt,
    this.updatedAt
  });

  factory User.fromJson(Map<String, dynamic> json){
    return User(
      id: json['id'],
      name: json['name'],
      description: json['description'],
      createdAt: DateTime.parse(json['created_at']),
      updatedAt: DateTime.parse(json['updated_at']),
    );
  }
}


class Team {
  int id;
  String? name;
  String? region;
  DateTime? createdAt;
  DateTime? updatedAt;

  Team({
    required this.id,
    this.name,
    this.region,
    this.createdAt,
    this.updatedAt,
  });

  factory Team.fromJson(Map<String, dynamic> json){
    return Team(
      id: json['id'],
      name: json['name'],
      region: json['region'],
      createdAt: DateTime.parse(json['created_at']),
      updatedAt: DateTime.parse(json['updated_at']),
    );
  }
}
 

Ответ API

 
{
  "status": 200,
  "message": "Returned",
  "data": [
    {
      "id": 1,
      "name": "Trevo Mgino",
      "description": "A Description",
      "created_at": "2021-09-29T06:47:03.000000Z",
      "updated_at": "2021-09-29T06:47:03.000000Z"
    }
  ],
}
 
 {
  "status": 200,
  "message": "Activated",
  "data": [
    {
      "id": 1,
      "name": "Team A",
      "region": "Region 1",
      "created_at": "2021-09-29T06:47:03.000000Z",
      "updated_at": "2021-09-29T06:47:03.000000Z"
    },
    {
      "id": 2,
      "name": "Team B",
      "region": "Region 1",
      "created_at": "2021-09-29T06:47:03.000000Z",
      "updated_at": "2021-09-29T06:47:03.000000Z"
    }
  ],
}
 

Комментарии:

1. просто расшифруйте свой json и передайте эту команду json.formjson(json)

Ответ №1:

Team.fromJson принимает a Map<String, dynamic> в качестве параметров, но вы даете ему a List<Map<String, dynamic>> .

Я думаю, что вы хотите изменить первое выражение, которое вы дали:

 ApiResponse<Team>.fromJson(
  json.decode(response.body),
  (data) => data.map((teamJson) => Team.fromJson(teamJson)),
)
 

Кроме того, вы можете ввести безопасный код, который использует ваша фабрика:

 class ApiResponse<T> {
  int status;
  String? message;
  T data;

  ApiResponse({
    required this.status,
    this.message,
    required this.data,
  });

  factory ApiResponse.fromJson(
    Map<String, dynamic> json,
    T Function(List<Map<String, dynamic>>) create,
  ) {
    return ApiResponse<T>(
      status: json['status'],
      message: json['message'],
      data: create(json['data']),
    );
  }
}
 

Если вы сделаете это, вам также придется снова изменить свое первое выражение, чтобы написать правильный тип (я думаю, что вы ошиблись, но, возможно, я ошибаюсь).:

 ApiResponse<List<Team>>.fromJson(
  json.decode(response.body),
  (data) => data.map((teamJson) => Team.fromJson(teamJson)).toList(),
);
 

Ответ №2:

Таким образом, мне удалось решить проблемы со следующим кодом:

 // Maps the API response to object
class ApiResponse<T> {
  int status;
  String? message;
  T data;

  ApiResponse({
    required this.status,
    this.message,
    required this.data,
  });

  factory ApiResponse.fromJson(Map<String, dynamic> json, List<T> Function(List<dynamic>) create) {
    return ApiResponse<T>(
      status: json['status'],
      message: json['message'],
      data: create(json['data']),
    );
  }
}
 

Вызов картографа

 return ApiResponse<Team>.fromJson(json.decode(response.body),
      (data) => data.map((tData) => Team.fromJson(tData)).toList());