0

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>'
2
  • can you also include your api response? Commented Nov 21, 2022 at 15:52
  • @eamirho3ein I have Commented Nov 21, 2022 at 15:58

2 Answers 2

1

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();
Sign up to request clarification or add additional context in comments.

2 Comments

@KennedyOwusu I updated my answer, check it out.
I tried this and it worked. Thank you @eamirho3ein
1

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

1 Comment

I tried this and it worked. Thank you @powerman23rus

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.