2

I am trying to make API calls in a flutter. While parsing a simple JSON it works fine but while I try to parse a List it shows error how can I do that?

My JSON

  {
  "posts": [
    {
      "id": 1,
      "title": "Post 1"
    },
    {
      "id": 2,
      "title": "Post 2"
    },
    {
      "id": 3,
      "title": "Post 3"
    }
  ],
  "comments": [
    {
      "id": 1,
      "body": "some comment",
      "postId": 1
    },
    {
      "id": 2,
      "body": "some comment",
      "postId": 1
    }
  ],
  "profile": {
    "name": "typicode"
  }
}

My PODO Class

    class Welcome {
    List<Post> posts;
    List<Comment> comments;
    Profile profile;

    Welcome({
        this.posts,
        this.comments,
        this.profile,
    });

    factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
        posts: List<Post>.from(json["posts"].map((x) => Post.fromJson(x))),
        comments: List<Comment>.from(json["comments"].map((x) => Comment.fromJson(x))),
        profile: Profile.fromJson(json["profile"]),
    );

    Map<String, dynamic> toJson() => {
        "posts": List<dynamic>.from(posts.map((x) => x.toJson())),
        "comments": List<dynamic>.from(comments.map((x) => x.toJson())),
        "profile": profile.toJson(),
    };
}

class Comment {
    int id;
    String body;
    int postId;

    Comment({
        this.id,
        this.body,
        this.postId,
    });

    factory Comment.fromJson(Map<String, dynamic> json) => Comment(
        id: json["id"],
        body: json["body"],
        postId: json["postId"],
    );

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

class Post {
    int id;
    String title;

    Post({
        this.id,
        this.title,
    });

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

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

class Profile {
    String name;

    Profile({
        this.name,
    });

    factory Profile.fromJson(Map<String, dynamic> json) => Profile(
        name: json["name"],
    );

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

My api_call.dart file

import 'dart:convert';

import 'package:api/api/modal.dart';
import 'package:http/http.dart';

class HttpService{

  final String url = "https://my-json-server.typicode.com/typicode/demo/db";

  Future<List<Welcome>> getPost() async {

    Response response = await get(url);

    if(response.statusCode == 200) {
     List<dynamic> body = jsonDecode(response.body);
     List<Welcome> wel = body.map((e) => Welcome.fromJson(e)).toList();
     return wel;
    }

  }
}

My widget.dart

import 'package:api/api/api_fetcher.dart';
import 'package:api/api/modal.dart';
import 'package:flutter/material.dart';

class News extends StatefulWidget {

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

class _NewsState extends State<News> {

  final HttpService http = HttpService();

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: DefaultTabController(
        length: 4,
        child: Scaffold(
          backgroundColor: Colors.white,
          appBar: AppBar(
            backgroundColor: Colors.white,
            title: Text(
              'Trending Topics',
              style: TextStyle(color: Colors.black, fontSize: 25),
            ),
            automaticallyImplyLeading: false,
            elevation: 0,
            actions: <Widget>[
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 10),
                child: Center(
                  child: Text(
                    'see all',
                    style: TextStyle(fontSize: 20, color: Colors.grey[600]),
                  ),
                ),
              ),
            ],
            bottom: TabBar(
              labelColor: Colors.black,
              unselectedLabelColor: Colors.black,
              tabs: <Widget>[
                Tab(
                  text: 'Tech',
                ),
                Tab(
                  text: 'Art',
                ),
                Tab(
                  text: 'Sports',
                ),
                Tab(
                  text: 'Nation',
                ),
              ],
            ),
          ),
          body: TabBarView(
            children: <Widget>[
              Container(
                child: FutureBuilder(
                  future: http.getPost(),
                  builder: (context, snapshot) {
                    if(snapshot.hasData){
                      List<Welcome> welc = snapshot.data;
                      return ListView(
                        children: welc.map((Welcome welcome) => ListTile(
                          title: Text(welcome.posts.length.toString()),
                        )),
                      );
                      }
                  },
                ),
              ),
              Container(),
              Container(),
              Container(),
            ],
          ),
        ),
      ),
    );
  }
}

It shows me an error while I try to access the posts through the ListTile.

Give me a solution, please.

Thanks in advance.

1
  • 1
    Please, post the error you're getting. Commented May 14, 2020 at 10:16

2 Answers 2

1

This json have one Welcome class, so your function that getPost() should be return just Welcome, consequence you should change your widget that show just welcome with list of post and/or list of comment. Try like this:

class Welcome {
  List<Post> posts;
  List<Comment> comments;
  Profile profile;

  Welcome({
    this.posts,
    this.comments,
    this.profile,
  });

  factory Welcome.fromJson(Map<String, dynamic> json) {
    return Welcome(
      posts: json['posts'] != null
          ? json['posts'].map<Post>((json) => Post.fromJson(json)).toList()
          : null,
      comments: json['comments'] != null
          ? json['comments']
              .map<Comment>((json) => Comment.fromJson(json))
              .toList()
          : null,
      profile:
          json['profile'] != null ? Profile.fromJson(json['profile']) : null,
    );
  }
}

class HttpService {
  static String url = "https://my-json-server.typicode.com/typicode/demo/db";

  static Future<Welcome> getPost() async {
    Response response = await get(url);

    if (response.statusCode == 200) {
      final parsed = json.decode(response.body).cast<String, dynamic>();
      return Welcome.fromJson(parsed);
    }
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot, sir it worked. Are there any more complex things to learn in API call?? can you suggest to me I am a noob in flutter so if you guide I can learn more. Thanks, sir.
fortunately Flutter have good documentation, I recommended to see documentation Link
0

In your code, you used map to map some objects and then assigned them to children of a widget, also use .toList() after the map.

Something that I couldn't get from you code is that you have a Wellcome model that contains a list of posts and comments and a profile, your sample JSON is equal to one Welcome but in your code when you fetched the data you tried to map it as a list of Wellcome also in your widget.

The other thing is in the future builder, it's better to define what type it is going to get:

...
FutureBuilder<Welcome>(
    future: http.getPost(),
    builder: (context, AsyncSnapshot<Welcome> snapshot) {

...

Also future takes some times to complete so in cases it doesn't have data(not completed yet) you should return another widget, here I simply used:

return Center(child: CircularProgressIndicator());

I changed your code a little bit, here is the result:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(MaterialApp(
    home: News(),
  ));
}

class Welcome {
  List<Post> posts;
  List<Comment> comments;
  Profile profile;

  Welcome({
    this.posts,
    this.comments,
    this.profile,
  });

  factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
        posts: List<Post>.from(json["posts"].map((x) => Post.fromJson(x))),
        comments: List<Comment>.from(
            json["comments"].map((x) => Comment.fromJson(x))),
        profile: Profile.fromJson(json["profile"]),
      );

  Map<String, dynamic> toJson() => {
        "posts": List<dynamic>.from(posts.map((x) => x.toJson())),
        "comments": List<dynamic>.from(comments.map((x) => x.toJson())),
        "profile": profile.toJson(),
      };
}

class Comment {
  int id;
  String body;
  int postId;

  Comment({
    this.id,
    this.body,
    this.postId,
  });

  factory Comment.fromJson(Map<String, dynamic> json) => Comment(
        id: json["id"],
        body: json["body"],
        postId: json["postId"],
      );

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

class Post {
  int id;
  String title;

  Post({
    this.id,
    this.title,
  });

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

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

class Profile {
  String name;

  Profile({
    this.name,
  });

  factory Profile.fromJson(Map<String, dynamic> json) => Profile(
        name: json["name"],
      );

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

class HttpService {
  final String url = "https://my-json-server.typicode.com/typicode/demo/db";

  Future<Welcome> getPost() async {
    var response = await http.get(url);

    if (response.statusCode == 200) {
      var body = json.decode(response.body);
      return Welcome.fromJson(body);
    }
  }
}

class News extends StatefulWidget {
  @override
  _NewsState createState() => _NewsState();
}

class _NewsState extends State<News> {
  final HttpService http = HttpService();

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: DefaultTabController(
        length: 4,
        child: Scaffold(
          backgroundColor: Colors.white,
          appBar: AppBar(
            backgroundColor: Colors.white,
            title: Text(
              'Trending Topics',
              style: TextStyle(color: Colors.black, fontSize: 25),
            ),
            automaticallyImplyLeading: false,
            elevation: 0,
            actions: <Widget>[
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 10),
                child: Center(
                  child: Text(
                    'see all',
                    style: TextStyle(fontSize: 20, color: Colors.grey[600]),
                  ),
                ),
              ),
            ],
            bottom: TabBar(
              labelColor: Colors.black,
              unselectedLabelColor: Colors.black,
              tabs: <Widget>[
                Tab(
                  text: 'Tech',
                ),
                Tab(
                  text: 'Art',
                ),
                Tab(
                  text: 'Sports',
                ),
                Tab(
                  text: 'Nation',
                ),
              ],
            ),
          ),
          body: TabBarView(
            children: <Widget>[
              Container(
                child: FutureBuilder<Welcome>(
                  future: http.getPost(),
                  builder: (context, AsyncSnapshot<Welcome> snapshot) {
                    if (snapshot.hasData) {
                      Welcome welc = snapshot.data;
                      return ListView(
                          children: welc.posts
                              .map((post) => ListTile(
                                    title: Text(post.title),
                                  ))
                              .toList());
                    }
                    return Center(child: CircularProgressIndicator());
                  },
                ),
              ),
              Container(),
              Container(),
              Container(),
            ],
          ),
        ),
      ),
    );
  }
}

3 Comments

Thanks a lot, sir it worked. Are there any more complex things to learn in API call?? can you suggest to me I am a noob in flutter so if you guide I can learn more. Thanks, sir.
You're welcome, you can search it in Flutter cookbook like this and Medium, you can go for handling exceptions in API, you can go for architectures, like adding a repository between API class and UI, like this, I'm learning too.
If any of the answers solved your problem you'd better accept it as the answer to be removed from unanswered questions.