Home > Mobile >  Constant Error - Type List Dynamic Is Not A Subtype Of Type Map String Dynamic
Constant Error - Type List Dynamic Is Not A Subtype Of Type Map String Dynamic

Time:11-22

I am consuming data from an API and whenever I try to do so, I keep getting this error. Type List Dynamic Is Not A Subtype Of Type Map String Dynamic

In my attempt to find answers, I came across this Similar Question

I have also gone through this Another Similar Question

And this as well A similar question again

From this similar question, I realized that there seems to be a data structure mismatch but I can't seem to get the solution to it.

Below are excerpts of my code

This is the Object Model


class Book {
  int? id = 0;
  String? title = "";
  String? description = "";
  String? image = "";
  String? author = "";

  Book({
    this.id,
    this.title,
    this.description,
    this.image,
    this.author,
  });

  Book.fromJson(Map<String, dynamic> parsedJson) {
    id = parsedJson['id'];
    title = parsedJson['title'];
    description = parsedJson['description'];
    image = parsedJson['image'];
    author = parsedJson['author'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['id'] = this.id;
    data['title'] = this.title;
    data['description'] = this.description;
    data['image'] = this.image;
    data['author'] = this.author;
    return data;
  }
}

This is the Controller Class that seems to contain the error. I am able to print the content coming from the backend though.


import 'dart:io';

import 'package:elibrary/model/books.dart';
import 'package:elibrary/services/repository/book_repository.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class BookController extends GetxController {
  BookRepository bookRepository = BookRepository();

  RxBool isLoading = false.obs;
  RxList<Book> bookList = <Book>[].obs;

  @override
  void onInit() {
    super.onInit();
    fetchBooksList();
  }

  Future<void> fetchBooksList() async {
    isLoading(true);

    try {
      Response bookResponse = await bookRepository.fetchBooks();
      if (bookResponse.statusCode == 200) {
        
        for (var element in bookResponse.body) {
          bookList.add(Book.fromJson(element));
        }
        
      } else {
        Get.snackbar(
          'Error Occurred',
          bookResponse.statusText.toString(),
          snackPosition: SnackPosition.BOTTOM,
          colorText: Colors.white,
          backgroundColor: Colors.red,
        );
      }
    } catch (e) {
      debugPrint(
        e.toString(),
      );
      Get.snackbar(
        "Error Occurred",
        e.toString(),
        snackPosition: SnackPosition.BOTTOM,
        colorText: Colors.white,
        backgroundColor: Colors.green,
        duration: Duration(seconds: 5),
      ).show();
    } finally {
      isLoading(false);
    }
  }
}

I did try changing the model object to this


import 'dart:convert';

Book bookFromJson(String str) => Book.fromJson(json.decode(str));

String bookToJson(Book data) => json.encode(data.toJson());

class Book {
    Book({
        this.id,
        this.title,
        this.description,
        this.image,
        this.author,
    });

    int id;
    String title;
    String description;
    String image;
    String author;

    factory Book.fromJson(Map<String, dynamic> json) => Book(
        id: json["id"],
        title: json["title"],
        description: json["description"],
        image: json["image"],
        author: json["author"],,
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "title": title,
        "description": description,
        "image": image,
        "author": author,
    };
}

And then I tried the controller this way also


import 'dart:io';

import 'package:elibrary/model/books.dart';
import 'package:elibrary/services/repository/book_repository.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class BookController extends GetxController {
  BookRepository bookRepository = BookRepository();

  RxBool isLoading = false.obs;
  RxList<Book> bookList = <Book>[].obs;

  @override
  void onInit() {
    super.onInit();
    fetchBooksList();
  }

  Future<void> fetchBooksList() async {
    isLoading(true);

    try {
      Response bookResponse = await bookRepository.fetchBooks();
      if (bookResponse.statusCode == 200) {

        bookList.assAll( 
            bookFromJson(bookResponse.bodyString ?? ''),
          )

      } else { 
        Get.snackbar(
          'Error Occurred',
          bookResponse.statusText.toString(),
          snackPosition: SnackPosition.BOTTOM,
          colorText: Colors.white,
          backgroundColor: Colors.red,
        );
      }
    } catch (e) {
      debugPrint(
        e.toString(),
      );
      Get.snackbar(
        "Error Occurred",
        e.toString(),
        snackPosition: SnackPosition.BOTTOM,
        colorText: Colors.white,
        backgroundColor: Colors.green,
        duration: Duration(seconds: 5),
      ).show();
    } finally {
      isLoading(false);
    }
  }
}

```

```


Again I tried decoding the response this way 


```

```
     var jsonList = jsonDecode(bookResponse.bodyString ?? '')
            .map((book) => Book.fromJson(book))
            .toList();
        bookList.assignAll(jsonList);
        debugPrint('Total Book List is: ${bookList.length}');

All these attempts produce the same error.

These is the API Response

I/flutter ( 5788): key = data, value = [{id: 1, name: dolore, icon: http://192.168.1.102:8000/images/categories/https://via.placeholder.com/640x480.png/007766?text=architecto}, {id: 2, name: repellat, icon: http://192.168.1.102:8000/images/categories/https://via.placeholder.com/640x480.png/004444?text=voluptatum}, {id: 3, name: est, icon: http://192.168.1.102:8000/images/categories/https://via.placeholder.com/640x480.png/005577?text=et}, {id: 4, name: quasi, icon: http://192.168.1.102:8000/images/categories/https://via.placeholder.com/640x480.png/00cc00?text=deserunt}, {id: 5, name: provident, icon: http://192.168.1.102:8000/images/categories/https://via.placeholder.com/640x480.png/008888?text=et}, {id: 6, name: quo, icon: http://192.168.1.102:8000/images/categories/https://via.placeholder.com/640x480.png/007777?text=dolorem}, {id: 7, name: expedita, icon: http://192.168.1.102:8000/images/categories/https://via.placeholder.com/640x480.png/00aa88?text=adipisci}, {id: 8, name: quia, icon: http://192.168.1.102:8000/images/categor
I/flutter ( 5788): result = {"data":[{"id":1,"name":"dolore","icon":"http:\/\/192.168.1.102:8000\/images\/categories\/https:\/\/via.placeholder.com\/640x480.png\/007766?text=architecto"},{"id":2,"name":"repellat","icon":"http:\/\/192.168.1.102:8000\/images\/categories\/https:\/\/via.placeholder.com\/640x480.png\/004444?text=voluptatum"},{"id":3,"name":"est","icon":"http:\/\/192.168.1.102:8000\/images\/categories\/https:\/\/via.placeholder.com\/640x480.png\/005577?text=et"},{"id":4,"name":"quasi","icon":"http:\/\/192.168.1.102:8000\/images\/categories\/https:\/\/via.placeholder.com\/640x480.png\/00cc00?text=deserunt"},{"id":5,"name":"provident","icon":"http:\/\/192.168.1.102:8000\/images\/categories\/https:\/\/via.placeholder.com\/640x480.png\/008888?text=et"},{"id":6,"name":"quo","icon":"http:\/\/192.168.1.102:8000\/images\/categories\/https:\/\/via.placeholder.com\/640x480.png\/007777?text=dolorem"},{"id":7,"name":"expedita","icon":"http:\/\/192.168.1.102:8000\/images\/categories\/https:\/\/via.placeholder.com\/640x480.png\/0

I/flutter ( 5788): Total Book List is: 0

I/flutter ( 5788): type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'

CodePudding user response:

Your response is map, you need use ["data"] on it to get your list you want. So in your Book class change this:

Book bookFromJson(String str) => Book.fromJson(json.decode(str));

to this:

List<Book> bookFromJson(String str) => (json.decode(str)["data"] as List).map((e) => Book.fromJson(e)).toList();

CodePudding user response:

You are receiving a JSON list and you have to pass each item of it to Book.parseJson function.

List<Book> bookFromJson(String str) {
  Iterable jsonArray = json.decode(str);
  return List<Book>.from(jsonArray.map((json) => Book.fromJson(json)));
}
  • Related