jsonflutterflutter-http

Error: type 'List<dynamic>' is not a subtype of type 'String' in Flutter


I'm learning to fetch a data from an API using mockapi.

I followed the flutter examples using the HTTP package but there's something wrong with the code and I can't seem to figure it out.

I have tried several APIs the one with headers and the one without it.

store_groceries_api.dart

class Groceries {
  final int id;
  final String name;
  final String images;

  const Groceries({required this.id, required this.name, required this.images});

  factory Groceries.fromJson(Map<String, dynamic> json) {
    return Groceries(
        id: json['id'], name: json['name'], images: json['images']);
  }
}

Future<Groceries> fetchGroceries() async {
  final response = await http.get(Uri.parse(
      'https://6453dd71e9ac46cedf31d94e.mockapi.io/api/v1/groceries'));

  if (response.statusCode == 200) {
    final responseJson = jsonDecode(response.body);

    return Groceries.fromJson(responseJson);

  } else {
    throw Exception("Failed to load groceries");
  }
}

explore_screen.dart


class ExplorePage extends StatefulWidget {
  const ExplorePage({Key? key}) : super(key: key);

  @override
  _ExplorePageState createState() => _ExplorePageState();
}

class _ExplorePageState extends State<ExplorePage>
    with AutomaticKeepAliveClientMixin {
  late Future<Groceries> futureGroceries;
  @override
  void initState() {
    super.initState();
    futureGroceries = fetchGroceries();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      body: ListView(
        children: [
          CarouselSlider(
            items: const [
              Padding(
                padding: EdgeInsets.all(20.0),
                child: Text('Placeholder'),
              ),
              Padding(
                padding: EdgeInsets.all(20.0),
                child: Text('Placeholder'),
              ),
              Padding(
                padding: EdgeInsets.all(20.0),
                child: Text('Placeholder'),
              ),
              Padding(
                padding: EdgeInsets.all(20.0),
                child: Text('Placeholder'),
              )
            ],
            options: CarouselOptions(
              autoPlay: true,
            ),
          ),
          FutureBuilder<Groceries>(
            future: futureGroceries,
            builder: (context, AsyncSnapshot snapshot) {
              if (snapshot.hasData) {
                ListView.builder(
                    padding: const EdgeInsets.all(10),
                    itemCount: 4,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: Text(snapshot.data!.name),
                      );
                    });
              } else if (snapshot.hasError) {
                return Text('${snapshot.error}');
              }

              return const CircularProgressIndicator();
            },
          )
        ],
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

The data im trying to read

[
 {
  "name": "name 1",
  "images": "images 1",
  "id": "1"
 },
 {
  "name": "name 2",
  "images": "images 2",
  "id": "2"
 },
 {
  "name": "name 3",
  "images": "images 3",
  "id": "3"
 },
 {
  "name": "name 4",
  "images": "images 4",
  "id": "4"
 }
]

Sorry if the codes are poorly made. As you can probably realize the if statement in the explore_screen.dart returned an error but the response status is 200

if (snapshot.hasData) {
  ListView.builder(
      padding: const EdgeInsets.all(10),
      itemCount: 4,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(snapshot.data!.name),
        );
      });
} else if (snapshot.hasError) {
  return Text('${snapshot.error}');
}

A help would be appreciated


Solution

  • You are getting list of items from api, it will be

    Future<List<Groceries>> fetchGroceries() async {
      .....
      if (response.statusCode == 200) {
        final responseJson = jsonDecode(response.body);
        return List.from(responseJson).map((e) => Groceries.fromJson(e)).toList();
      } else {
        throw Exception("Failed to load groceries");
      }
    }