I'm excited to share insights into the world of HTTP requests in Flutter and how they play a vital role in mobile app development. Before diving into practical examples, I'd like to direct your attention to a couple of resources that can complement and expand your understanding of this topic.
I've created a YouTube video that delves into the very topic we're about to explore. In the video, I demonstrate the execution of HTTP requests in a Flutter environment, providing a visual guide that might enhance your understanding. You can find the video here. (Highly Recommended)
Additionally, I've curated a repository on GitHub where you can find relevant code snippets, supplementary materials, and resources related to the examples we'll be discussing. The GitHub repository is accessible here.
Let's embark on this journey together, discovering the power and versatility of HTTP requests within Flutter and how they drive dynamic data interactions in mobile applications.
Utilizing the http
Package
Flutter's http
package simplifies the process of making HTTP requests and handling responses. Let's explore two sample codes showcasing GET and POST requests.
Sample Code 1: Performing a POST Request
The following code demonstrates how to send data to a server using a POST request:
import 'dart:async';
import 'dart:convert';
import 'package:apitutorial/home.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> createAlbum(String title) async {
final response = await http.post(
Uri.parse('https://jsonplaceholder.typicode.com/albums'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'title': title,
}),
);
if (response.statusCode == 201) {
// If the server did return a 201 CREATED response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 201 CREATED response,
// then throw an exception.
throw Exception('Failed to create album.');
}
}
class Album {
final int id;
final String title;
const Album({required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
id: json['id'] as int,
title: json['title'] as String,
);
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
final TextEditingController _controller = TextEditingController();
Future<Album>? _futureAlbum;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Create Data Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: Scaffold(
appBar: AppBar(
title: const Text('Create Data Example'),
),
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(8),
child: (_futureAlbum == null) ? buildColumn() : buildFutureBuilder(),
),
),
);
}
Column buildColumn() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
decoration: const InputDecoration(hintText: 'Enter Title'),
),
ElevatedButton(
onPressed: () {
setState(() {
_futureAlbum = createAlbum(_controller.text);
});
},
child: const Text('Create Data'),
),
],
);
}
FutureBuilder<Album> buildFutureBuilder() {
return FutureBuilder<Album>(
future: _futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
);
}
}
This code is a simple Flutter application that demonstrates creating an album by sending a POST request to a mock API endpoint using the http
package in Dart. Here's a breakdown of the major components:
Import Statements
- Importing necessary Dart and Flutter packages like
async
,http
,material
, andjson
.
Album Class
Album
class represents an album with anid
andtitle
. It contains a constructor and afromJson
factory method to convert JSON data into anAlbum
object.
createAlbum Function
createAlbum
is an asynchronous function that uses thehttp.post
method to send a POST request to the specified API endpoint ('https://jsonplaceholder.typicode.com/albums').It sends a JSON payload containing the album
title
in the request body.If the request is successful (returns a status code of 201 - Created), it parses the response JSON and creates an
Album
object using thefromJson
factory method.If the request fails or returns a different status code, it throws an exception indicating the failure to create an album.
Main Function
main
function sets up the Flutter application by running theMyApp
widget.
MyApp Class
MyApp
is a stateful widget that defines the root of the application.
_MyAppState Class
_MyAppState
is the state associated withMyApp
and contains the text controller for the input field and aFuture<Album>
object to handle the asynchronous creation of an album.
build Method
The
build
method sets up the UI of the application.It configures the app's theme and defines the
Scaffold
with anAppBar
and a body.The body contains a container with a column widget, which contains a text field for entering the album title and a button to trigger the creation of the album.
buildColumn Method
buildColumn
returns a column containing a text field and a button.The button triggers the creation of the album by calling the
createAlbum
function when pressed.
buildFutureBuilder Method
buildFutureBuilder
returns aFutureBuilder
widget. It displays different UI elements based on the state of the asynchronous operation (_futureAlbum
).If the operation is complete and successful, it displays the title of the created album.
If there's an error during the operation, it displays the error message.
While the operation is in progress, it displays a circular progress indicator.
The application allows users to enter a title for an album, create it via a POST request, and displays the result or error message accordingly using Flutter's FutureBuilder
.
This code showcases a function createAlbum
that sends a POST request to a server. It includes an Album
class representing the structure of an album and a UI setup in the MyApp
class allowing users to input an album title and create an album.
Sample Code 2: Performing a GET Request
Let's take a look at the code that fetches data from a server using a GET request:
import 'package:apitutorial/model/response/list_of_response.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:cached_network_image/cached_network_image.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List<ListOfData> _list = [];
Future<List<ListOfData>> getAllData() async {
try {
final response =
await http.get(Uri.parse('https://fakestoreapi.com/products'));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
_list = data.map<ListOfData>((e) => ListOfData.fromJson(e)).toList();
debugPrint('${_list.length}');
return _list;
} else {
debugPrint(
'Error in API call Please check your backend and URL carefully');
}
return _list;
} catch (e) {
debugPrint('$e');
}
return _list;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: getAllData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: _list.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
title: Text('${_list[index].title}'),
subtitle: Text('${_list[index].description}'),
leading: SizedBox(
height: 50,
width: 50,
child: CachedNetworkImage(
imageUrl: '${_list[index].image}',
progressIndicatorBuilder: (context, url, progress) =>
CircularProgressIndicator(
value: progress.progress),
),
),
trailing: Text('${_list[index].price}'),
);
});
} else if (snapshot.hasError) {
return const Text("Error");
}
return const Text("No Data");
}),
);
}
}
This code represents a Flutter StatefulWidget
named HomeScreen
that fetches data from a specified API endpoint and displays the information in a ListView
.
Here's a breakdown of the code:
Import Statements
- Various package imports are included such as
material
from Flutter,http
for making HTTP requests,cached_network_image
for efficiently loading and caching network images, andjson
for encoding and decoding JSON data.
HomeScreen Class
HomeScreen
is aStatefulWidget
representing the main screen of the application.
_HomeScreenState Class
_HomeScreenState
manages the state for theHomeScreen
.
State Variables
_list
is a list ofListOfData
objects.
getAllData Method
getAllData
is an asynchronous function that makes an HTTP GET request to 'https://fakestoreapi.com/products' to fetch data.If the response status is 200 (OK), the JSON response is decoded and used to populate the
_list
by mapping the JSON data toListOfData
objects (presumably defined in 'list_of_response.dart').Debug print statements are used to display the count of items fetched or any error encountered during the API call.
build Method
The
build
method configures the UI for theHomeScreen
.It displays a
Scaffold
containing aFutureBuilder
that waits for the result ofgetAllData
.When data is received, it displays a
ListView.builder
widget, populating the list with data fetched from the API.- Each list item is represented by a
ListTile
containing text fields for the title, description, and price. It also includes aCachedNetworkImage
widget for loading and displaying the product image.
- Each list item is represented by a
The FutureBuilder
is responsible for showing different UI components based on the current state of the asynchronous operation:
If data is available, it displays the list of items fetched from the API.
If there is an error during the API call, it shows an error message.
If no data is available, it displays a message indicating the absence of data.
This code provides a basic structure to fetch data from an API and display it in a list format, including images loaded from network URLs using the cached_network_image
package to ensure efficient caching and loading of images in the Flutter app.
Both sample codes illustrate practical implementations of making HTTP requests in Flutter using the http
package. The first code focuses on creating data through a POST request, while the second code emphasizes retrieving and displaying data via a GET request.
Continuing the article with a discussion on best practices, error handling, and the nuances of using Flutter's HTTP library would complement the multimedia content and provide a comprehensive guide for readers interested in networking with Flutter applications.