Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does FutureBuilder snapshot.data return "Instance of Post" instead of json?

Tags:

http

flutter

dart

I'm expecting a JSON object of data but instead am getting Instance of 'Post'

I'm new to flutter and trying to hit an API with a post request using http.dart package. I'm using an async future and a future building to populate a widget with the returned data (following the flutter example here: https://flutter.io/docs/cookbook/networking/fetch-data).

Future<Post> fetchPost() async {
  String url = "https://example.com";

  final response = await http.post(url,
      headers: {HttpHeaders.contentTypeHeader: 'application/json'},
      body: jsonEncode({"id": "1"}));

  if (response.statusCode == 200) {
    print('RETURNING: ' + response.body);
    return Post.fromJson(json.decode(response.body));
  } else {
    throw Exception('Failed to load post');
  }
}


class Post {
  final String title;

  Post({this.title});

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      title: json['title']
    );
  }
}


void main() => runApp(MyApp(post: fetchPost()));

class MyApp extends StatelessWidget {
  final Future<Post> post;

  MyApp({Key key, this.post}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Fetch Data Example'),
        ),
        body: Center(
          child: FutureBuilder<Post>(
            future: post,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text(snapshot.data.toString());
              } else if (snapshot.hasError) {
                return Text("${snapshot.error}");
              }
              // By default, show a loading spinner
              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

I'm expecting the return statement in the FutureBuilder to give me a json object. This is an existing API so I know it works and it returns what I'm expecting.

like image 954
T Fisher Avatar asked Jan 04 '19 22:01

T Fisher


1 Answers

I am not sure what you refer to when you say "JSON object". Dart is a typed language and the way you represent anything coming as a json string is either a nested Map<String, dynamic> or a class (like in your case). If it is a class there is code that performs the actual de-/serialization. In your case the fromJson method in conjunction with the json.decode() can do the deserialization, but you have nothing for serialization yet.

So your future builder is returning what you ask it to. The following piece of code defines the type of future clearly returning a Post object:

  final Future<Post> post;

and you use it when creating your future builder:

  child: FutureBuilder<Post>(
    future: post,

If you want a JSON String (or a Map<String,dynamic>) returned you need to start by doing that in your fetchPost method (which currently is also returning a Post object.

For example:

Future<Map<String, dynamic>> fetchPost() async { // <------ CHANGED THIS LINE
  String url = "https://example.com";

  final response = await http.post(url,
      headers: {HttpHeaders.contentTypeHeader: 'application/json'},
      body: jsonEncode({"id": "1"}));

  if (response.statusCode == 200) {
    print('RETURNING: ' + response.body);
    return json.decode(response.body); // <------ CHANGED THIS LINE
  } else {
    throw Exception('Failed to load post');
  }
}

or like this:

Future<String> fetchPost() async { // <------ CHANGED THIS LINE
  String url = "https://example.com";

  final response = await http.post(url,
      headers: {HttpHeaders.contentTypeHeader: 'application/json'},
      body: jsonEncode({"id": "1"}));

  if (response.statusCode == 200) {
    print('RETURNING: ' + response.body);
    return response.body; // <------ CHANGED THIS LINE
  } else {
    throw Exception('Failed to load post');
  }
}

Then you need to work your way up until you change the Future in your MyApp class.

final Future<Map<String,dynamic>> post;

Please read these docs to learn about JSON in flutter.

like image 196
Oswin Noetzelmann Avatar answered Sep 22 '22 01:09

Oswin Noetzelmann