165

I am using the dart package json_serializable for json serialization. Looking at the flutter documentation it shows how to deserialize a single object as follow:

Future<Post> fetchPost() async {
  final response =
  await http.get('https://jsonplaceholder.typicode.com/posts/1');

  if (response.statusCode == 200) {
  // If the call to the server was successful, parse the JSON
  return Post.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load post');
  }
}

However, I am not familiar enough with dart to figure out how to do the same for a list of items instead of a single instance.

1
  • 3
    well, it decodes the response body, and passes it into essentially a POST constructor. If your decoded JSON is an array, you would need to loop it and build an array of Posts. Is that what you are asking? check the type of the decode to ensure it is an iterable and then do something akin to: List<Post> posts = json.decode(response.body).map((Map m)=> Json.fromJson(m)).toList(); Commented Jun 27, 2018 at 3:05

13 Answers 13

200

Well, your service would handle either the response body being a map, or a list of maps accordingly. Based on the code you have, you are accounting for 1 item.

If the response body is iterable, then you need to parse and walk accordingly, if I am understanding your question correctly.

Example:

Iterable l = json.decode(response.body);
List<Post> posts = List<Post>.from(l.map((model)=> Post.fromJson(model)));

where the post is a LIST of posts.

EDIT: I wanted to add a note of clarity here. The purpose here is that you decode the response returned. The next step, is to turn that iterable of JSON objects into an instance of your object. This is done by creating fromJson methods in your class to properly take JSON and implement it accordingly. Below is a sample implementation.

class Post {
  // Other functions and properties relevant to the class
  // ......
  /// Json is a Map<dynamic,dynamic> if i recall correctly.
  static fromJson(json): Post {
    Post p = new Post()
    p.name = ...
    return p
  }
}

I am a bit abstracted from Dart these days in favor of a better utility for the tasks needing to be accomplished. So my syntax is likely off just a little, but this is Pseudocode.

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

12 Comments

I seem to get some internal casting error when I try this. _TypeError (type '(Map<dynamic, dynamic>) => UserInfoV1' is not a subtype of type '(dynamic) => dynamic' of 'f')
This is a brilliant solution and can be mixed with jsonserializer lib, but it has an error in map function (maybe the dart version changed the api) List<Post> posts = l.map((model)=> Post.fromJson(model)).toList();
correct solution is: List< Item > itemsList= List< Item >.from(parsedListJson.map((i) => Item.fromJson(i))); the above code is invalid syntax and will not compile
Thank you @Quinn. Maybe Dart has changed slightly over the years, so i presume some things would have changed. I guess toList is not the correct syntax any longer, and that Array.from() is the best solution these days?
.toList() seems to still turn an iterable into a list, but the problem is with the dynamic type. it doesn't seem to want to turn it from dynamic into Post inside of the List generic.
|
119

I always use this way with no problem;

List<MyModel> myModels;
var response = await http.get("myUrl");

myModels=(json.decode(response.body) as List).map((i) =>
              MyModel.fromJson(i)).toList();

9 Comments

very straight to the point and solves the problem. You can as well use this use the URL below to map your JSON string to a dart class. javiercbk.github.io/json_to_dart
This URL always save my time, but needs attention for variables comes with null values. And I prefer to change the code blocks to my style if needed for nested object lists.
Actually, I am confusing with fromJson, where it comes from?
@Bayu from json is a factory function defined in your model. if you use, app.quicktype.io or javiercbk.github.io/json_to_dart websites to create models from your json they will create everything for you.
Where is this fromJson coming from?
|
58

You can also Do it like

  List<dynamic> parsedListJson = jsonDecode("your json string");
  List<Item> itemsList = List<Item>.from(parsedListJson.map<Item>((dynamic i) => Item.fromJson(i)));

where Item is your custom class, where you implemented toJson and fromJson.

5 Comments

THIS IS THE ONLY SOLUTION THAT WORKED FOR ME ^^^^^^^^^^^^^^^^^^^^^ everything else gave compile errors relating to not being able to cast dynamic to the object type i am trying to unmarshal to
Where is parsedListJson located? Is it from a Dart or 3rd party package? I get an error, Undefined name 'parsedListJson'..
I get it now. It's the List you're looking to parse (i.e. it's not an element of the framework).
This worked for me. I have List<PlayingCard> cards that could easily be encoded into a JSON Array of PlayingCards. Decoding was cumbersome, but this apporach worked!
To help the struggling newcomers to dart. Instead of "your json string", I used the response.body from the http.get call like: List<dynamic> parsedListJson = jsonDecode(response.body);
22

Just another example on JSON Parsing for further clarification.

Let say we want to parse items array in our JSON Object.

factory YoutubeResponse.fromJSON(Map<String, dynamic> YoutubeResponseJson) 
 {

// Below 2 line code is parsing JSON Array of items in our JSON Object (YouttubeResponse)


var list = YoutubeResponseJson['items'] as List;
List<Item> itemsList = list.map((i) => Item.fromJSON(i)).toList();

return new YoutubeResponse(
    kind: YoutubeResponseJson['kind'],
    etag: YoutubeResponseJson['etag'],
    nextPageToken: YoutubeResponseJson['nextPageToken'],
    regionCode: YoutubeResponseJson['regionCode'],
    mPageInfo: pageInfo.fromJSON(YoutubeResponseJson['pageInfo']),

    // Here we are returning parsed JSON Array.

    items: itemsList);

  }

2 Comments

Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<Item>'
can you please post some part of your json response.
12

First, create a class that matches your json data, in my case, I create (generate) class named Img:

import 'dart:convert';

Img imgFromJson(String str) => Img.fromJson(json.decode(str));
String imgToJson(Img data) => json.encode(data.toJson());

class Img {
    String id;
    String img;
    dynamic decreption;

    Img({
        this.id,
        this.img,
        this.decreption,
    });

    factory Img.fromJson(Map<String, dynamic> json) => Img(
        id: json["id"],
        img: json["img"],
        decreption: json["decreption"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "img": img,
        "decreption": decreption,
    };
}

PS. You can use app.quicktype.io to generate your json data class in dart. then send your post/get to your server:

Future<List<Img>> _getimages() async {
    var response = await http.get("http://192.168.115.2/flutter/get_images.php");
    var rb = response.body;

    // store json data into list
    var list = json.decode(rb) as List;

    // iterate over the list and map each object in list to Img by calling Img.fromJson
    List<Img> imgs = list.map((i)=>Img.fromJson(i)).toList();

    print(imgs.runtimeType); //returns List<Img>
    print(imgs[0].runtimeType); //returns Img

    return imgs;
}

for more info see Parsing complex JSON in Flutter

Comments

11

Full example

Here a full example of JSON serialization and deserialization for Object, List<Object>. Here we have a Main class which is composed by a nested Sub class and a List<Sub>.

Json sample

{
    "title": "something",
    "sub": {"name": "a", "num": 0},
    "sub_list": [
      {"name": "b", "num": 1},
      {"name": "c", "num": 2}
    ]
}

Main class

class Main {
  String title;
  Sub sub;
  List<Sub> subList;

  Main(this.title, this.sub, this.subList);

  Main.fromJson(Map<String, dynamic> json)
      : title = json['title'],
        sub = Sub.fromJson(json['sub']),
        subList = List<dynamic>.from(json['sub_list'])
            .map((i) => Sub.fromJson(i))
            .toList();

  Map<String, dynamic> toJson() => {
        'title': title,
        'sub': sub.toJson(),
        'sub_list': subList.map((item) => item.toJson()).toList(),
      };
}

Sub class

class Sub {
  String name;
  int n;

  Sub(this.name, this.n);

  Sub.fromJson(Map<String, dynamic> json)
      : name = json['name'],
        n = json['n'];

  Map<String, dynamic> toJson() => {
        'name': name,
        'n': n,
      };
}

usage

void main(List<String> args) {
  var sub = Sub("a", 0);
  print(sub.name); // a

  Map<String, dynamic> jsonSub = {"name": "a", "n": 0};
  var subFromJson = Sub.fromJson(jsonSub);
  print(subFromJson.n); // 0

  var main = Main("something", Sub("a", 0), [Sub("b", 1)]);
  print(main.title); // something
  print(main.sub.name); // a
  print(main.subList[0].name); // b

  var jsonMain = {
    "title": "something",
    "sub": {"name": "a", "n": 0},
    "sub_list": [
      {"name": "b", "n": 1},
      {"name": "c", "n": 2}
    ]
  };
  var mainFromJson = Main.fromJson(jsonMain);
  print(mainFromJson.title); // something
  print(mainFromJson.sub.name); // a
  print(mainFromJson.subList[0].name); // b
  print(mainFromJson.subList[1].name); // c
}

2 Comments

+1 for actually showing how your solution fits into the code around it, so for being complete. You might want to add something like // <== THIS IS THE CRUX OF IT, ENUMERATE EACH ITEM AND ENCODE THEM
-1 for cheating :-) You are not using JSON (which is a string) but Map<String, dynamic> objects, whereas the whole point of the excercise is to convert between an object and a JSON string. Thus, "var mainFromJson = Main.fromJson(jsonMain);" in real life would need more work, like "var mainFromJson = Main.fromJson(convert().jsonDecode("<string containting JSON>"))". Anyway, you put me on a path to solving my problem, so thank you!
5

With strong-mode enabled none of the above solutions will actually compile as type information is missing.

This compiles as of dart 2.14 with strong mode enabled:

analysis_options.yaml


include: package:lints/recommended.yaml

analyzer:
  strong-mode:
    implicit-casts: false
    implicit-dynamic: false

    import 'dart:convert';

    // read the json file. This example use dcli but you just
    // need [source] to contain the json string.
    var source = dcli.read(_failedTrackerFilename).toParagraph();

    var l = json.decode(source) as Iterable;
    var failures = List<UnitTest>.from(l.map<UnitTest>(
          (dynamic i) => UnitTest.fromJson(i as Map<String, dynamic>)));

Comments

4

Follow these steps:

  1. Create a model class (named as LoginResponse): click here to convert json to dart .

  2. LoginResponce loginResponce=LoginResponce.fromJson(json.decode(response.body));

  3. Now you get your data in instence of model (as loginResponce ).

1 Comment

this is an amazing method. instead of setting up the dart code generation or taking hours with figuring out the specifics of deserialization, it is an online deserializer for testing piloting, experimenting. nice answer, thx
3

This is my Model class -

  class SuggestedMovie {
  String title;
  String genres;
  int movieId;
  SuggestedMovie({this.title, this.genres, this.movieId});
  factory SuggestedMovie.fromJson(Map<dynamic, dynamic> parsedJson) {
    return SuggestedMovie(
      movieId: parsedJson['movieId'],
      title: parsedJson['title'] as String,
      genres: parsedJson['genres'] as String,
    );
  }
}

The one below is the code for Deserializing the JSON response into List

 suggestedMovie = (json.decode(jsonResponse.data) as List)
      .map((i) => SuggestedMovie.fromJson(i))
      .toList();

Comments

3

Sometimes, the problem arise for the structure of JSON and for your Pojo class.

My JSON is as follows:

{"records":[{"name":"noor ","email":"email","mobileNo":187,"feedback":"good"}]}

According to this JSON we have to create the pojo classes right way. When you paste your JSON it will give you the pojo class in this site: https://javiercbk.github.io/json_to_dart/

You have to give a class name there. With name of question I found the following two pojo classes according to the above JSON:

class Questions {
  List<Records>? records;

  Questions({this.records});

  Questions.fromJson(Map<String, dynamic> json) {
    if (json['records'] != null) {
      records = <Records>[];
      json['records'].forEach((v) {
        records!.add(new Records.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.records != null) {
      data['records'] = this.records!.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Records {
  String? name;
  String? email;
  int? mobileNo;
  String? feedback;

  Records({this.name, this.email, this.mobileNo, this.feedback});

  Records.fromJson(Map<String, dynamic> json) {
    name = json['name'];
    email = json['email'];
    mobileNo = json['mobileNo'];
    feedback = json['feedback'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['name'] = this.name;
    data['email'] = this.email;
    data['mobileNo'] = this.mobileNo;
    data['feedback'] = this.feedback;
    return data;
  }
}

Now the important part: that convert that record to list. Here is the calling:

Future<List<Records>> getRecordList() async {
    return await http.get(Uri.parse(URL)).then((response) {
      print(response.body.toString());

      Questions questions = Questions.fromJson(json.decode(response.body));

     

      print(questions.records![0].feedback);

      List<Records> list_s = [];
      for (int i = 0; i < questions.records!.length; i++) {
        list_s.add(questions.records![i]);
      }

      print(list_s[0].name);

      return list_s;
    });
  }
}

And At last the UI part Is :

class _FeedbackListPageState extends State<FeedbackListPage> {
 
  List<Records> list_s = [];
  

  @override
  void initState() {
    super.initState();

    FormController().getRecordList().then((value) {
      setState(() {
        list_s = value;
      });
    });

    
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: darkGreen,
        elevation: 0.0,
        titleSpacing: 10.0,
        title: Text(widget.title),
        centerTitle: true,
        leading: InkWell(
          onTap: () {
            Navigator.pop(context);
          },
          child: const Icon(
            Icons.arrow_back_ios,
            color: Colors.black54,
          ),
        ),
      ),
      body: ListView.builder(
        itemCount: list_s.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Row(
              children: <Widget>[
                Icon(Icons.person),
                Expanded(
                  child: Text("${list_s[index].name} (${list_s[index].email})"),
                )
              ],
            ),
            subtitle: Row(
              children: <Widget>[
                Icon(Icons.message),
                Expanded(
                  child: Text(list_s[index].feedback.toString()),
                )
              ],
            ),
          );
        },
      ),
    );
  }
}

Comments

3

What I did to solve the problem was the following:

List<YourItemClass> items = [];

final data = jsonDecode(resp.body); //Here it goes your json array

for (dynamic item in data) {
    items.add(YourItemClass.fromMap(item));
}

return items;

Of course you need to have a fromMap() method in YourItemClass, if you do not, you can get it in quicktype.io pasting one single json instance of your class (and selecting dart language).

Comments

1

Simply you can typecast your date like the below.

class SubCategories {
  String? id;
  String? name;
  String? detailsIcon;
  List<SubCategoriesList>? subCategorieslist = [];

  SubCategories(this.id, this.name, this.detailsIcon, this.subCategorieslist);

  SubCategories.fromJson(Map json) {
    id = json["_id"];
    detailsIcon = json["detailsIcon"];
    name = json["name"];
    json["subCategories"]!.forEach((v) {
      subCategorieslist!.add(SubCategoriesList.fromJson(v));
    });
    subCategorieslist = subCategorieslist;
  }
}

Comments

1

Parse data class from json array:

import 'dart:convert';

...

final http.Response response = await http.get(uri, headers: headers);
if (response.statusCode == 200) {
      final List<dynamic> jsonArray = jsonDecode(response.body);
      final List<DataClass> data = jsonArray
                                   .map((jsonObject) => DataClass.fromJson(jsonObject))
                                   .toList(growable: false);
} 

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.