DEV Community

Cover image for Flutter Dio HTTP Client

Posted on • Updated on


Flutter Dio HTTP Client

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:

  dio: ^4.0.4
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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) {
      ..baseUrl = ''
      ..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), () {
Enter fullscreen mode Exit fullscreen mode

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.

multiple concurrent requests
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'/info', data: formData);
Enter fullscreen mode Exit fullscreen mode


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 {
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    super.onRequest(options, handler);
    log("Request Path: ${options.path}");
    log("Request Query Parameters: ${options.queryParameters}");

  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: ${}");

  void onError(DioError err, ErrorInterceptorHandler handler) {
    super.onError(err, handler);
    log("Error Status Code: ${err.response?.statusCode}");
    log("Error Status Message: ${err.response?.statusMessage}");

Enter fullscreen mode Exit fullscreen mode

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) {
Enter fullscreen mode Exit fullscreen mode


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.

Top comments (1)

ammar_abu_srour profile image