0

I have built the following using a combination of several examples and cannot get the results to display. This is my first attempt at using flutter/dart for a macos app so there are probably many mistakes. I am using the API demo at http://dummy.restapiexample.com/ and https://app.quicktype.io/ to generate the parsing logic.

The error I get in the app is: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'FutureOr<Data>'

In the app I enter the name Joe and the age 32. I can see from the debug output that the http.post is working correctly: flutter: {status: success, data: {name: Joe, salary: 123, age: 32, id: 95}}

main.dart

import 'package:flutter/material.dart';
import 'package:apitestapp/widgets/ApiTest.dart';

var text = TextEditingController();

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

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

class _MyAppState extends State<MyApp> {
bool pressed = false;
final myController1 = TextEditingController();
final myController2 = TextEditingController();

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ApiTest',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('ApiTest'),
        ),
        body:
        Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          TextField(
            controller: myController1,
            decoration: InputDecoration(
            hintText: 'Enter your name',
            hintStyle: TextStyle(color: Colors.grey)
            ),
           ),
           TextField(
            controller: myController2,
            decoration: InputDecoration(
            hintText: 'Enter your age',
            hintStyle: TextStyle(color: Colors.grey)
            ),
           ),
          RaisedButton(
            child: Text('Get ApiTest Data'),
            onPressed: () {
              nameTest = myController1.text;
              ageTest = myController2.text;
              print("Data sent: Name is $nameTest and age is $ageTest");
              setState(() {
              pressed = true;
              });
            },
          ),
          ApiTest(),
        ],
        ),
      ),
    );
  }
}

ApiTest.dart

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

String nameTest = "";
String ageTest = "";

// From https://app.quicktype.io/
Welcome welcomeFromJson(String str) => Welcome.fromJson(json.decode(str));

String welcomeToJson(Welcome data) => json.encode(data.toJson());

class Welcome {
    String status;
    Data data;

    Welcome({
        this.status,
        this.data,
    });

    factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
        status: json["status"],
        data: Data.fromJson(json["data"]),
    );

    Map<String, dynamic> toJson() => {
        "status": status,
        "data": data.toJson(),
    };
}

class Data {
    String name;
    String salary;
    String age;
    String id;

    Data({
        this.name,
        this.salary,
        this.age,
        this.id,
    });

    factory Data.fromJson(Map<String, dynamic> json) => Data(
        name: json["name"],
        salary: json["salary"],
        age: json["age"],
        id: json["id"],
    );

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

class ApiTest extends StatefulWidget {
  ApiTest({Key key}) : super(key: key);

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

class _ApiTestState extends State<ApiTest> {

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

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Data>(
      future: fetchPost(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
        return Row(
          children: [
              Text(snapshot.data.name),
              Text(snapshot.data.age),
          ],
        );
        } else if (snapshot.hasError) {
          return Text("${snapshot.error}");
        }
        return CircularProgressIndicator();
        },
      );
    }
  Future<Data> fetchPost() async {
    var url = "http://dummy.restapiexample.com/api/v1/create";
    var body = json.encode({"name":"$nameTest","salary":"123","age":"$ageTest"});

    Map<String,String> headers = {
      'Content-type' : 'application/json', 
      'Accept': 'application/json',
    };

  final response = await http.post(url, body: body, headers: headers);
  final responseJson = json.decode(response.body);
  print(responseJson);
  return responseJson;
  }
}

App Screenshot

Thanks for any help.

2 Answers 2

1

You can copy paste run full code below

Step 1: revised fetchPost()

 Welcome welcome = welcomeFromJson(response.body);  
 return welcome.data;

Step 2: change id from String to int

class Data {
  String name;
  String salary;
  String age;
  int id;

working demo

enter image description here

full code

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

String nameTest = "";
String ageTest = "";

// From https://app.quicktype.io/
Welcome welcomeFromJson(String str) => Welcome.fromJson(json.decode(str));

String welcomeToJson(Welcome data) => json.encode(data.toJson());

class Welcome {
  String status;
  Data data;

  Welcome({
    this.status,
    this.data,
  });

  factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
    status: json["status"],
    data: Data.fromJson(json["data"]),
  );

  Map<String, dynamic> toJson() => {
    "status": status,
    "data": data.toJson(),
  };
}

class Data {
  String name;
  String salary;
  String age;
  int id;

  Data({
    this.name,
    this.salary,
    this.age,
    this.id,
  });

  factory Data.fromJson(Map<String, dynamic> json) => Data(
    name: json["name"],
    salary: json["salary"],
    age: json["age"],
    id: json["id"],
  );

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

class ApiTest extends StatefulWidget {
  ApiTest({Key key}) : super(key: key);

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

class _ApiTestState extends State<ApiTest> {

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

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Data>(
      future: fetchPost(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return Row(
            children: [
              Text(snapshot.data.name),
              Text(snapshot.data.age),
            ],
          );
        } else if (snapshot.hasError) {
          return Text("${snapshot.error}");
        }
        return CircularProgressIndicator();
      },
    );
  }
  Future<Data> fetchPost() async {
    var url = "http://dummy.restapiexample.com/api/v1/create";
    var body = json.encode({"name":"$nameTest","salary":"123","age":"$ageTest"});

    Map<String,String> headers = {
      'Content-type' : 'application/json',
      'Accept': 'application/json',
    };

    final response = await http.post(url, body: body, headers: headers);
    //final responseJson = json.decode(response.body);
    print(response.body);
    Welcome welcome = welcomeFromJson(response.body);
    //print(responseJson);
    return welcome.data;
  }
}

var text = TextEditingController();

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

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

class _MyAppState extends State<MyApp> {
  bool pressed = false;
  final myController1 = TextEditingController();
  final myController2 = TextEditingController();

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ApiTest',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('ApiTest'),
        ),
        body:
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            TextField(
              controller: myController1,
              decoration: InputDecoration(
                  hintText: 'Enter your name',
                  hintStyle: TextStyle(color: Colors.grey)
              ),
            ),
            TextField(
              controller: myController2,
              decoration: InputDecoration(
                  hintText: 'Enter your age',
                  hintStyle: TextStyle(color: Colors.grey)
              ),
            ),
            RaisedButton(
              child: Text('Get ApiTest Data'),
              onPressed: () {
                nameTest = myController1.text;
                ageTest = myController2.text;
                print("Data sent: Name is $nameTest and age is $ageTest");
                setState(() {
                  pressed = true;
                });
              },
            ),
            ApiTest(),
          ],
        ),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

This is because you're not using a future in your FutureBuilder. Your fetchPost() method is returning a map (your decoded json) when it really should be returning the future from http.post(...) instead of waiting for it to complete.

Ideally Instead of decoding the json in your fetchPost() method, you should just return the http.post(...) call (as it returns a future) and then process the snapshot inside of your FutureBuilder.

This video is a great example on how to apply the FutureBuilder: https://www.youtube.com/watch?v=ek8ZPdWj4Qo

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.