0
0
Fluttermobile~20 mins

GET and POST requests in Flutter - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Simple API Client
This screen fetches a list of items from a server using a GET request and allows the user to add a new item using a POST request.
Target UI
-------------------------
| Simple API Client      |
-------------------------
| Items:                |
| - Item 1              |
| - Item 2              |
|                       |
| New Item: [________]  |
| [Add Item Button]     |
-------------------------
Fetch a list of items from a public API using a GET request when the screen loads.
Display the list of items in a scrollable list.
Provide a TextField for the user to enter a new item name.
Add a button labeled 'Add Item' that sends the new item to the server using a POST request.
Show a loading indicator while fetching or posting data.
Display a simple message if the list is empty or if an error occurs.
Starter Code
Flutter
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class SimpleApiClient extends StatefulWidget {
  @override
  _SimpleApiClientState createState() => _SimpleApiClientState();
}

class _SimpleApiClientState extends State<SimpleApiClient> {
  List<String> items = [];
  bool isLoading = false;
  final TextEditingController controller = TextEditingController();

  @override
  void initState() {
    super.initState();
    // TODO: Fetch items from API
  }

  Future<void> fetchItems() async {
    // TODO: Implement GET request
  }

  Future<void> addItem(String newItem) async {
    // TODO: Implement POST request
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Simple API Client')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Expanded(
              child: isLoading
                  ? Center(child: CircularProgressIndicator())
                  : items.isEmpty
                      ? Center(child: Text('No items found.'))
                      : ListView.builder(
                          itemCount: items.length,
                          itemBuilder: (context, index) {
                            return ListTile(title: Text(items[index]));
                          },
                        ),
            ),
            TextField(
              controller: controller,
              decoration: InputDecoration(labelText: 'New Item'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () {
                // TODO: Call addItem with text from controller
              },
              child: Text('Add Item'),
            ),
          ],
        ),
      ),
    );
  }
}
Task 1
Task 2
Task 3
Task 4
Task 5
Task 6
Solution
Flutter
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class SimpleApiClient extends StatefulWidget {
  @override
  _SimpleApiClientState createState() => _SimpleApiClientState();
}

class _SimpleApiClientState extends State<SimpleApiClient> {
  List<String> items = [];
  bool isLoading = false;
  final TextEditingController controller = TextEditingController();

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

  Future<void> fetchItems() async {
    setState(() {
      isLoading = true;
    });
    try {
      final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
      if (response.statusCode == 200) {
        final List<dynamic> data = json.decode(response.body);
        setState(() {
          items = data.map((item) => item['title'] as String).toList();
        });
      } else {
        setState(() {
          items = [];
        });
      }
    } catch (e) {
      setState(() {
        items = [];
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }

  Future<void> addItem(String newItem) async {
    if (newItem.isEmpty) return;
    setState(() {
      isLoading = true;
    });
    try {
      final response = await http.post(
        Uri.parse('https://jsonplaceholder.typicode.com/posts'),
        headers: {'Content-Type': 'application/json; charset=UTF-8'},
        body: json.encode({'title': newItem, 'body': '', 'userId': 1}),
      );
      if (response.statusCode == 201) {
        setState(() {
          items.insert(0, newItem);
          controller.clear();
        });
      }
    } catch (e) {
      // Could show error message here
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Simple API Client')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Expanded(
              child: isLoading
                  ? Center(child: CircularProgressIndicator())
                  : items.isEmpty
                      ? Center(child: Text('No items found.'))
                      : ListView.builder(
                          itemCount: items.length,
                          itemBuilder: (context, index) {
                            return ListTile(title: Text(items[index]));
                          },
                        ),
            ),
            TextField(
              controller: controller,
              decoration: InputDecoration(labelText: 'New Item'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: isLoading
                  ? null
                  : () {
                      addItem(controller.text.trim());
                    },
              child: Text('Add Item'),
            ),
          ],
        ),
      ),
    );
  }
}

This Flutter app uses the http package to make network requests.

When the screen opens, fetchItems() sends a GET request to a public API and extracts the titles from the JSON response to show as a list.

The user can type a new item name in the TextField and tap the 'Add Item' button. This triggers addItem(), which sends a POST request with the new item data.

While waiting for the network, a loading spinner shows. After a successful POST, the new item is added to the top of the list and the input clears.

This simple example shows how to handle GET and POST requests, update UI state, and manage user input in Flutter.

Final Result
Completed Screen
-------------------------
| Simple API Client      |
-------------------------
| Items:                |
| - sunt aut facere     |
| - qui est esse        |
| - ea molestias quasi  |
|                       |
| New Item: [________]  |
| [Add Item Button]     |
-------------------------
When the screen loads, a spinner shows briefly while items load from the API.
The list of item titles appears in a scrollable list.
User types a new item name in the text field.
Tapping 'Add Item' sends the new item to the server and adds it to the top of the list.
While adding, the button disables and a spinner shows.
If the list is empty, a message 'No items found.' is shown.
Stretch Goal
Add error messages that show a SnackBar if the GET or POST request fails.
💡 Hint
Use ScaffoldMessenger.of(context).showSnackBar() inside the catch blocks to show a simple message.