ahmed2hamy
Posted on February 8, 2022
Most of Flutter apps needs to make network calls to give more value to your app or to fulfill business needs. In this article we will take a look at how to handle REST API requests in Flutter.
What Is Dio?
Flutter offers a basic HTTP package but to use the full power of Rest Api you might need to consider using Dio it's a powerful Http client, which supports Interceptors, Global configuration, FormData, Request Cancellation, File downloading, Timeout etc.
Getting Started
Let’s get started by creating a new Flutter project and add Dio package to your pubspec.yaml file:
dependencies:
dio: ^4.0.4
Initialize Dio
You can create a separate class containing the methods for performing the network operations. This helps to separate the functional logic from the user interface code.
To do this, create a new file network_client.dart containing the NetworkClient class:
class NetworkClient{
// TODO: Set up and define the methods for network
operations
}
You can initialize Dio in the class or preferably use dependency injection to have more control on life cycle and to make your dependencies decoupled to achieve separation of concerns.
import 'dart:_http';
import 'dart:async';
import 'package:dio/dio.dart';
class NetworkClient {
final Dio _dio;
NetworkClient(this._dio) {
_dio.options
..baseUrl = 'http://httpbin.org/'
..connectTimeout = 5000 //5s
..receiveTimeout = 5000
..validateStatus = (int? status) {
return status != null && status > 0;
}
..headers = {
HttpHeaders.userAgentHeader: 'dio',
'common-header': 'xx',
};
// Token can be shared with different requests.
var token = CancelToken();
// In one minute, we cancel!
Timer(Duration(milliseconds: 500), () {
token.cancel('cancelled');
});
}
}
Now, we can define the methods required for performing the network requests.
Defining requests
GET is used to request data from a specified resource.
POST is used to send data to a server to create/update a resource.
The difference between POST and PUT is that PUT requests are idempotent. That is, calling the same PUT request multiple times will always produce the same result. In contrast, calling a POST request repeatedly have side effects of creating the same resource multiple times.
The DELETE method deletes the specified resource.
The PATCH method applies partial modifications to a resource.
Performing multiple concurrent requests.
Uploading Files and Formdata
Dio makes the process of uploading files to a server much simpler. It can process multiple simultaneous file uploads and has a simple callback for tracking their progress, which makes it much easier to use than the http package.
You can easily upload files to a server using FormData and Dio. Here’s an example of what sending files to the API would look like:
var formData = FormData.fromMap({
'name': 'wendux',
'age': 25,
'file': await MultipartFile.fromFile('./text.txt', filename: 'upload.txt'),
'files': [
await MultipartFile.fromFile('./text1.txt', filename: 'text1.txt'),
await MultipartFile.fromFile('./text2.txt', filename: 'text2.txt'),
]
});
var response = await dio.post('/info', data: formData);
Interceptors
You can intercept Dio requests, responses, and errors before they are handled by using then or catchError. In a practical scenario, interceptors are useful for authorization, parsing JSON, handling errors, and easily debugging Dio network requests.
You can run the interceptor by overriding the callbacks at three places: onRequest, onResponse, and onError.
For our example, we will define a simple interceptor for logging different types of requests. Create a new class called LoggingInterceptor that extends from Interceptor:
import 'dart:developer';
import 'package:dio/dio.dart';
class LoggingInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
super.onRequest(options, handler);
log("Request Path: ${options.path}");
log("Request Query Parameters: ${options.queryParameters}");
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
super.onResponse(response, handler);
log("Response Status Code: ${response.statusCode}");
log("Response Status Message: ${response.statusMessage}");
log("Response Data: ${response.data}");
}
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
super.onError(err, handler);
log("Error Status Code: ${err.response?.statusCode}");
log("Error Status Message: ${err.response?.statusMessage}");
}
}
Here, we have overridden various callbacks that get triggered by Dio requests and added a log statement to each of them for logging the requests in the console.
Add the interceptor to Dio during initialization:
import 'dart:_http';
import 'dart:async';
import 'package:dio/dio.dart';
class NetworkClient {
final Dio _dio;
NetworkClient(this._dio) {
_dio.interceptors.add(LoggingInterceptor());
...
}
Conclusion
Dio makes it easier to handle multiple simultaneous network requests, all with the safety of an advanced error handling technique. It also allows you to avoid the boilerplate code you’d need to use the http package for tracking any file upload progress. And there are various other advanced customizations that you can pull off using the Dio package that go beyond what we’ve covered here.
Thank you and have a great day.
Posted on February 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.