Author: Your Name | Date: October 2023
Introduction
Flutter is an open-source UI software development kit (SDK) created by Google,
which allows rapid development of applications that run on multiple platforms using a single codebase.
In this tutorial, we will explore the http
package, commonly used to communicate with external APIs in Flutter.
This package is a tool that simplifies communication with RESTful APIs.
Installing the http Package
To use the http package, you first need to add it to your pubspec.yaml
file.
Add the following code to the dependencies:
section:
dependencies:
http: ^0.13.4
After adding the package, use the following command to install it:
flutter pub get
Basic Usage
To use the http package, you first need to import the relevant classes.
Write your code like this to use the http package:
import 'package:http/http.dart' as http;
Now, let’s look at how to send a GET request to an external API.
For example, checking user information from the JSONPlaceholder API:
Future fetchData() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));
if (response.statusCode == 200) {
// When the request was successful
print('Data: ${response.body}');
} else {
// When the request failed
throw Exception('Failed to fetch data.');
}
}
The function above operates asynchronously,
it requests user information from the API, printing the data if the response is successful.
Sending a POST Request
Now, let’s look at how to send a POST request.
For example, when sending data to an API that creates a new user:
Future createUser() async {
final response = await http.post(
Uri.parse('https://jsonplaceholder.typicode.com/users'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode({
'name': 'John Doe',
'username': 'johndoe',
'email': 'johndoe@example.com',
}),
);
if (response.statusCode == 201) {
// User was successfully created.
print('User created: ${response.body}');
} else {
// When the request failed
throw Exception('Failed to create user');
}
}
In the above code, the `jsonEncode` function is a built-in JSON encoding function in Dart,
used to convert Dart objects into JSON-formatted strings.
Query Parameters and Headers
Let’s learn how to add query parameters in HTTP GET requests
and how to set request headers.
For example, you can filter data based on certain conditions:
Future fetchFilteredData() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users?filter=active'),
headers: {
'Authorization': 'Bearer some_api_key',
}
);
if (response.statusCode == 200) {
print('Filtered data: ${response.body}');
} else {
throw Exception('Failed to fetch filtered data.');
}
}
Here, `filter=active` is a query parameter provided by the API,
and the `Authorization` header is a way to provide authentication information to the server by including the API key.
Error Handling
When making API requests, you should always handle errors.
By checking the HTTP request’s status code and handling exceptions,
you can provide a better experience for users:
Future fetchDataWithErrorHandling() async {
try {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));
if (response.statusCode == 200) {
print('Data: ${response.body}');
} else {
throw Exception('Server Error: ${response.statusCode}');
}
} catch (e) {
print('Error occurred during request: $e');
}
}
The above code uses a try-catch statement to
handle potential exceptions that may occur during asynchronous requests.
Reusing the HTTP Client
Reusing the HTTP client can optimize performance and
allow for common use across multiple requests.
You can create an HTTP client like this:
class ApiService {
final http.Client client;
ApiService(this.client);
Future fetchData() async {
final response = await client.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));
// Same data processing logic as above...
}
}
// Example usage:
final apiService = ApiService(http.Client());
await apiService.fetchData();
By injecting the client into a class like this,
you can improve reusability and ease of testing.
Parsing JSON Data
You can parse JSON data received from an API for use.
It’s common practice to create model classes to consume the data internally:
class User {
final int id;
final String name;
final String username;
final String email;
User({required this.id, required this.name, required this.username, required this.email});
factory User.fromJson(Map json) {
return User(
id: json['id'],
name: json['name'],
username: json['username'],
email: json['email'],
);
}
}
The above model class shows how
to convert JSON data into objects.
Handling List Data
Let’s learn how to handle multiple JSON objects as a list.
To do this, you’ll need to properly transform the data received from the API:
Future> fetchUsers() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));
if (response.statusCode == 200) {
List jsonData = jsonDecode(response.body);
return jsonData.map((data) => User.fromJson(data)).toList();
} else {
throw Exception('Failed to fetch user list.');
}
}
This code parses the JSON data received from the server and
returns a list of user information.
Handling HTTP Redirection
Certain API requests may require handling redirection.
In this case, it is automatically handled when using http.Client
,
but let’s also look at how to manually handle redirection:
Future handleRedirect() async {
final response = await http.get(Uri.parse('https://httpbin.org/redirect/1'));
if (response.statusCode == 200) {
print('Final URL: ${response.request!.url}');
} else {
print('Request failed: ${response.statusCode}');
}
}
In the example above, it will automatically follow redirection for the HTTP request and output the final URL.
Comprehensive Example: Creating a CRUD Application
Based on what we have learned so far, let’s discuss how to implement a simple CRUD (Create, Read, Update, Delete) application.
For example, you can implement functionalities to add, retrieve, update, and delete users using the JSONPlaceholder API.
class UserApiService {
final http.Client client;
UserApiService(this.client);
Future> fetchUsers() async {
// Code to fetch users...
}
Future createUser(User user) async {
// Code to create a user...
}
Future updateUser(User user) async {
// Code to update a user...
}
Future deleteUser(int id) async {
final response = await client.delete(Uri.parse('https://jsonplaceholder.typicode.com/users/$id'));
// Logic for deletion...
}
}
The above example defines a `UserApiService` class that includes methods for CRUD operations.
You can add functionalities by implementing actual HTTP requests.