85

I am currently building an app to read data through an api and I am trying to parse a JSON api from JSON Placeholder.

I made a model class for the Users (users_future_model.dart):

class Users {
  final int userID;
  final String name;
  final String username;
  final String email;
  final Address address;

  Users({this.userID, this.name, this.username, this.email, this.address});

  factory Users.fromJson(Map<String, dynamic> usersjson)=> Users(
      userID: usersjson["id"],
      name: usersjson["name"],
      username: usersjson["username"],
      email: usersjson["email"],
      address: Address.fromJson(usersjson["address"])
  );
}

class Address{

  final String street;
  final String suite;
  final String city;
  final String zipcode;

  Address({this.street, this.suite, this.city, this.zipcode});

  factory Address.fromJson(Map<String, dynamic> addjson){

    return Address(
      street: addjson["street"],
      suite:  addjson["suite"],
      city: addjson["city"],
      zipcode: addjson["zipcode"]
    );
  }
}

This is the main.dart to read the json into the widget:

import 'package:flutter/material.dart';
import 'model/users_future_model.dart';
import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;

final String jsonplaceholder = "http://jsonplaceholder.typicode.com/users/";

//Future method to read the URL
Future<Users> fetchInfo() async{
  final response = await http.get(jsonplaceholder);
  final jsonresponse = json.decode(response.body);

  return Users.fromJson(jsonresponse);
}

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Parse JSON"),
      ),
      body: new Center(
        child: new Column(
          children: <Widget>[
            new FutureBuilder(
                future: fetchInfo(),
                builder: (context, snapshot){
                  if(snapshot.hasData){
                    return new Text(snapshot.data.email);
                  }else if(snapshot.hasError){
                    return new Text("Error ${snapshot.error}");
                  }
                })
          ],
        ),
      )
    );
  }
}

This is the JSON information i'm trying to read although its only a small part of it:

{
id: 1,
name: "Leanne Graham",
username: "Bret",
email: "[email protected]",
address: {
 street: "Kulas Light",
 suite: "Apt. 556",
 city: "Gwenborough",
 zipcode: "92998-3874",
 geo: {
  lat: "-37.3159",
  lng: "81.1496"
 }
},
phone: "1-770-736-8031 x56442",
website: "hildegard.org",
company: {
 name: "Romaguera-Crona",
 catchPhrase: "Multi-layered client-server neural-net",
 bs: "harness real-time e-markets"
}
}

The error i am currently running into is:

Error type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'

How do i rectify this error?

11 Answers 11

91

API returns JSON array not json object so that is List not Map.

i.e. User json is first element of Json Array.

So to get first element use first index. Inside fetch Info update

return Users.fromJson(jsonresponse[0]);

Sign up to request clarification or add additional context in comments.

2 Comments

return gameTypeResponseFromJson((response["data"]));
Thanks you very much brother. json array exactly that was my mistake . so thanks again.
51
var streetsFromJson = parsedJson['streets'];
List<String> streetsList = new List<String>.from(streetsFromJson);

Thnx for https://medium.com/flutter-community/parsing-complex-json-in-flutter-747c46655f51

3 Comments

A link to a solution is welcome, but please ensure your answer is useful without it: add context around the link so your fellow users will have some idea what it is and why it’s there, then quote the most relevant part of the page you're linking to in case the target page is unavailable. Answers that are little more than a link may be deleted.
It works for me with little tweaks as per my requirement
Muzaffar Abduboqiyev - your solution worked but when I use List<String> streetsList = streetsFromJson as List<String>; It does not work. Could you please suggest what is the issue. Thanks.
17

Check out this Answer

 Future<List<ProductList>> getProductList() async {
  print("comes");
  String productURl= mainURL+'api/store/product-with-category/';

  final response = await http.get(productURl,headers:{"Content-Type": 
 "application/json"});
  List jsonResponse = json.decode(response.body);
  return jsonResponse.map((job) => new ProductList.fromJson(job)).toList();
  
}

Fetch function

    FutureBuilder<List<ProductList>>(
    future: getProductList(),
    builder: (context, snapshot) {
      print("snapshot");
      print(snapshot.data);
      if (snapshot.hasData) {
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: GridView.builder(
          itemCount: snapshot.data.length,
            gridDelegate:SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2,),
            itemBuilder:  (BuildContext context, int i){
              return Card(
                child: Container(
                  decoration: BoxDecoration(
                      border: Border.all(width: 0.5,color: Colors.grey)
                  ),
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Column(
                      children: <Widget>[
                         text18(snapshot.data[i].title, Colors.black, FontWeight.bold)
                      ],
                    ),
                  ),
                ),
              );
            }
        )
        );
      } else if (snapshot.hasError) {
        return Text("${snapshot.error}");
      }


      // By default, show a loading spinner.
      return CircularProgressIndicator();
    },
  ),

just change URL and create model class

Comments

7

Pay attention to the error:

List<dynamic> is not a subtype of type Map<String, dynamic>

This means that the data that you are receiving after hitting a web service is in the form of a List, but the data class that you have used is of type Map. Therefore, it is unable to parse the data due to the structure mismatch, as Map is defined instead of List in the data class.

Recheck your Json response and corresponding PODO class

2 Comments

I am using FutureBuilder to return an Album data type in Flutter. How would I work around this error, because I can only return an Album?
Yes, I had to check my response and noticed it was returning an array instead of an object, on checking my network request route, I noticed I was making a request on the wrong request route which returns a list instead of an object, so changing to the correct route resolved mine, so check yours and see that you aren't doing same too.
1

Another way to do this easily:

import 'package:json_helpers/json_helpers.dart';

void main() {
  // If request returns list of users
  var body = '[{"id": 1}, {"id": 2} ]';
  final users = body.jsonList((e) => User.fromJson(e));
  assert(users[1].id == 2);
  print(users[1].id);

  // If request returns the user
  body = '{"id": 1}';
  final user = body.json((e) => User.fromJson(e));
  assert(user.id == 1);
  print(user.id);
}

Comments

0
import 'dart:convert';
List<User> userFromJson(String str) => List<User>.from(json.decode(str).map((x) => User.fromJson(x)));
class User {
  int? id;
  String? name;
  String? username;
  String? email;
  Address? address;
  String? phone;
  String? website;
  Company? company;
  factory User.fromJson(Map<String, dynamic> json) => User(
    id: json["id"],
    name: json["name"],
    username: json["username"],
    email: json["email"],
    //   address =
    //   json['address'] != null ? Address.fromJson(json['address']) : null;
    address :Address.fromJson(json['address']),// chua check null
    phone: json["phone"],
    website: json["website"],
    company :Company.fromJson(json['company']),// chua check null
  );
  User({
    required this.id,
    required this.name,
    required this.username,
    required this.email,
    required this.address,
    required this.phone,
    required this.website,
    required this.company,
  });

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data =  <String, dynamic>{};
    data['id'] = id;
    data['name'] = name;
    data['username'] = username;
    data['email'] = email;
    if (address != null) {
      data['address'] = address!.toJson();
    }
    data['phone'] = phone;
    data['website'] = website;
    if (company != null) {
      data['company'] = company!.toJson();
    }
    return data;
  }
}

class Address {
  String? street;
  String? suite;
  String? city;
  String? zipcode;
  Geo? geo;

  Address({this.street, this.suite, this.city, this.zipcode, this.geo});

  Address.fromJson(Map<String, dynamic> json) {
    street = json['street'];
    suite = json['suite'];
    city = json['city'];
    zipcode = json['zipcode'];
    geo = json['geo'] != null ? Geo.fromJson(json['geo']) : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['street'] = street;
    data['suite'] = suite;
    data['city'] = city;
    data['zipcode'] = zipcode;
    if (geo != null) {
      data['geo'] = geo!.toJson();
    }
    return data;
  }
}

class Geo {
  String? lat;
  String? lng;

  Geo({this.lat, this.lng});

  Geo.fromJson(Map<String, dynamic> json) {
    lat = json['lat'];
    lng = json['lng'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['lat'] = lat;
    data['lng'] = lng;
    return data;
  }
}

class Company {
  String? name;
  String? catchPhrase;
  String? bs;

  Company({this.name, this.catchPhrase, this.bs});

  Company.fromJson(Map<String, dynamic> json) {
    name = json['name'];
    catchPhrase = json['catchPhrase'];
    bs = json['bs'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['name'] = name;
    data['catchPhrase'] = catchPhrase;
    data['bs'] = bs;
    return data;
  }
}

import 'dart:core';
import 'package:demo_user_api_http/models/user.dart';
import 'package:http/http.dart' as http;

class RemoteService{
  Future<List<User>?> getUsers() async{
    var client = http.Client();

    var uri = Uri.parse('https://jsonplaceholder.typicode.com/users');
    var response = await client.get(uri);
    if (response.statusCode == 200) {
      var json = response.body;
      return userFromJson(json);
    }
    return null;
  }

List<User>? users;
  var isLoaded = false;
  @override
  void initState() {
    super.initState();
    getData();
  }
  getData() async {
    users = await RemoteService().getUsers();
    if (users != null) {
      setState(() {
        isLoaded = true;
      });
    }
  }

Comments

0

userList is api response

userListModalFromJson is the model name

jsonEncode(data) or json.encode(data)

 return userListModalFromJson(jsonEncode(data));

Comments

0

In my case this one is work perfectly

setState(() {
            var decodedResponse = data['data']['goods'];
            decodedResponse.forEach((e) {
              goodsModelData.add(Good.fromJson(e));
            });
            print("stateModelData[0].name $goodsModelData");

          });

Comments

0

Convert Firebase Object to List.

Use this function to read the Object? from firebase and convert to List.

void readDataFromDatabase() async {
    List<String> dataKey = [];
    List<String> dataValue = [];
    final DatabaseReference DBref =
      FirebaseDatabase.instance.ref("path/to/your/data");
    DatabaseEvent event = await DBref.once();
    DataSnapshot snapshot = event.snapshot;
    Object? data = snapshot.value;

    if (data is Map<dynamic, dynamic>) {
      for (var entry in data.entries) {
        dataKey.add((entry.key).toString());
        dataValue.add((entry.value).toString());
      }
    } else {
      print('Data is not of the expected Map<dynamic, dynamic> type.');
    }
    print('Key List: $dataKey');
    print('Value List: $dataValue');
}

thank you reading my answer 😊

Comments

0

First, you will create a userList list. You will synchronize the decoded code you receive from the API to the UserList list derived from the User model, not to the User Model.

exp: List<User> userList = [];

result =  jsondecode(responce.body);

userList =  jsonResponse.map((job) => new ProductList.fromJson(job)).toList();

return userList;

Now you can use model fields with userList's index.

Comments

-8

Use

List<dynamic> output = jsonDecode(yourJsonSource);

instead of

Map<String, dynamic> output = jsonDecode(yourJsonSource);

Comments

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.