Skip to content

About

Learning dio package.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

7 Commits

Folders and files

Repository files navigation

Dio Package Learning

This repository is focused on learning and implementing the Dio package in Flutter/Dart for handling HTTP requests, API communication, interceptors, CRUD operations, and clean API architecture.

What I Learned

1. Dio Setup

Learned how to add and configure the Dio package and create a centralized Dio instance for API communication.

Key concepts:

  • Dio()
  • BaseOptions
  • baseUrl
  • headers
  • connectTimeout
  • receiveTimeout
  • Request/response configuration
  • Centralized API configuration

2. Request & Response Handling

Learned how to send API requests and handle different types of responses.

GET Request

final response = await dio.get('/users');

POST Request

final response = await dio.post(
  '/users',
  data: {
    'name': 'Radhe',
    'email': 'radhe@example.com',
  },
);

PUT Request

final response = await dio.put(
  '/users/1',
  data: {
    'name': 'Updated Name',
  },
);

PATCH Request

final response = await dio.patch(
  '/users/1',
  data: {
    'name': 'Updated Name',
  },
);

DELETE Request

final response = await dio.delete('/users/1');

3. Handling List & Map Responses

Learned how to work with API responses returned as:

  • List
  • Map
  • Nested List and Map
  • Raw JSON
  • JSON converted into models

Example:

final response = await dio.get('/users');

final data = response.data;

For a list response:

List data = response.data;

For a map response:

Map<String, dynamic> data = response.data;

4. Working With Models

Learned how to convert API JSON responses into Dart models instead of working with raw maps everywhere.

Example:

final user = UserModel.fromJson(response.data);

For multiple objects:

final users = (response.data as List)
    .map((json) => UserModel.fromJson(json))
    .toList();

This makes the application more structured, readable, and type-safe.


5. CRUD Operations

Implemented and understood the complete CRUD flow using Dio.

Operation HTTP Method Purpose
Create POST Create new data
Read GET Fetch data
Update PUT Replace/update complete data
Partial Update PATCH Update specific fields
Delete DELETE Remove data

6. Headers

Learned how to send headers with API requests.

Example:

Options(
  headers: {
    'Authorization': 'Bearer token',
    'Content-Type': 'application/json',
  },
)

Headers can be configured globally or provided for individual requests.


7. Base URL

Learned how to configure a common baseUrl so API endpoints do not need to repeat the complete URL.

BaseOptions(
  baseUrl: 'https://example.com/api',
)

Then requests become:

dio.get('/users');

instead of:

dio.get('https://example.com/api/users');

8. Dio Options

Learned how to use Options and BaseOptions to configure requests.

Important options include:

  • baseUrl
  • headers
  • contentType
  • responseType
  • sendTimeout
  • receiveTimeout
  • connectTimeout

Example:

Options(
  headers: {
    'Authorization': 'Bearer token',
  },
  contentType: 'application/json',
)

Interceptors

One of the most important things learned in this repository is Dio Interceptors.

Interceptors allow us to execute logic before a request is sent, after a response is received, or when an error occurs.

There are three major interceptor callbacks:

onRequest
onResponse
onError

9. onRequest

Used to inspect or modify a request before it is sent to the server.

Example:

onRequest: (options, handler) {
  print('Request URL: ${options.uri}');
  print('Request Method: ${options.method}');
  print('Request Headers: ${options.headers}');
  print('Request Data: ${options.data}');

  handler.next(options);
}

This is useful for debugging and adding things such as authentication tokens.


10. onResponse

Used to inspect the response received from the server.

onResponse: (response, handler) {
  print('Response Status: ${response.statusCode}');
  print('Response Data: ${response.data}');

  handler.next(response);
}

11. onError

Used to handle and debug API errors.

onError: (error, handler) {
  print('Error: ${error.message}');
  print('Status Code: ${error.response?.statusCode}');
  print('Response: ${error.response?.data}');

  handler.next(error);
}

My Dio / Dio Injection Container

Created a centralized file such as:

mydio.dart

or

dio_injection_container.dart

The purpose of this file is to create and configure the Dio instance in one place.

Instead of configuring Dio repeatedly throughout the application, all common configuration is handled centrally.

Responsibilities

My Dio configuration handles:

  • Dio initialization
  • Base URL
  • Headers
  • Request configuration
  • Response configuration
  • Error handling
  • Interceptors
  • API debugging
  • Common options

Example structure:

final dio = Dio(
  BaseOptions(
    baseUrl: 'https://example.com/api',
    headers: {
      'Content-Type': 'application/json',
    },
  ),
);

dio.interceptors.add(
  InterceptorsWrapper(
    onRequest: (options, handler) {
      print('REQUEST: ${options.method} ${options.uri}');
      print('HEADERS: ${options.headers}');
      print('DATA: ${options.data}');

      handler.next(options);
    },
    onResponse: (response, handler) {
      print('RESPONSE: ${response.statusCode}');
      print('DATA: ${response.data}');

      handler.next(response);
    },
    onError: (error, handler) {
      print('ERROR: ${error.message}');
      print('STATUS: ${error.response?.statusCode}');
      print('DATA: ${error.response?.data}');

      handler.next(error);
    },
  ),
);

This makes API debugging much easier because I can see what is going through the API at a central location.


Clean Architecture

I also learned how to use Dio inside a Clean Architecture structure instead of putting API logic directly inside UI/screens.

A typical structure used in the project:

lib/
│
├── core/
│   └── network/
│       ├── mydio.dart
│       └── dio_injection_container.dart
│
├── data/
│   ├── models/
│   ├── datasources/
│   └── repositories/
│
├── domain/
│   ├── entities/
│   ├── repositories/
│   └── usecases/
│
└── presentation/
    ├── pages/
    └── widgets/

The main idea is to keep:

UI → UseCase → Repository → DataSource → Dio → API

This keeps API communication separated from the presentation layer.


API Debugging

A major focus of this repository was making API debugging easier.

For every request, I can inspect things such as:

========== REQUEST ==========
METHOD: GET
URL: https://example.com/api/users
HEADERS: {...}
DATA: null

========== RESPONSE ==========
STATUS: 200
DATA: [...]

========== ERROR ==========
STATUS: 404
MESSAGE: Not Found
DATA: {...}

This makes it much easier to identify:

  • Wrong endpoint
  • Wrong HTTP method
  • Missing headers
  • Incorrect request body
  • Authentication problems
  • Server errors
  • Unexpected response data
  • Parsing/model issues

HTTP Methods Learned

GET     → Fetch data
POST    → Create data
PUT     → Update/replace data
PATCH   → Partially update data
DELETE  → Delete data

Overall Learning

Through this repository, I learned how to use Dio beyond simply making API requests.

I learned how to:

  • Configure Dio
  • Create a reusable Dio instance
  • Configure BaseOptions
  • Configure baseUrl
  • Manage headers
  • Use request/response options
  • Perform GET, POST, PUT, PATCH and DELETE requests
  • Handle List and Map JSON responses
  • Convert JSON into Dart models
  • Use interceptors
  • Handle request, response and error interceptors
  • Debug API communication centrally
  • Structure networking code using Clean Architecture
  • Separate API/data logic from presentation logic

The main goal of this repository was to understand how production-style API communication can be organized in Flutter using Dio and Clean Architecture, rather than just learning individual HTTP methods.

About

Learning dio package.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages