Introduction
Integrating REST APIs is a core skill for Flutter mobile development. Dio is a powerful HTTP client for Dart that brings features like interceptors, global configuration, request cancellation, and robust error handling. This tutorial shows a practical, code-forward approach to using Dio for typical REST workflows: setup, configuration, requests, error handling, and response parsing.
Installing And Configuring Dio
Add dio to pubspec.yaml and run flutter pub get. Create a single Dio instance to reuse configuration across the app. Use BaseOptions to set baseUrl, timeouts, and default headers so individual requests remain concise and consistent.
Example configuration pattern that belongs in a service or provider layer:
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: 5000,
receiveTimeout: 3000,
headers: {'Accept': 'application/json'},
));Keep authentication tokens out of raw headers at creation time; inject them with an interceptor so token refresh logic can be centralized.
Making Requests And Handling Errors
Dio exposes async methods like get, post, put, and delete that return a Response object. Use try catch when awaiting requests to surface DioError types. Distinguish between response errors, timeouts, and cancellations to provide meaningful UI feedback.
Simple GET example to fetch a list of items. Note the response is dynamic and needs parsing.
Future<List<Map<String, dynamic>>> fetchItems() async {
try {
final resp = await dio.get('/items');
return List<Map<String, dynamic>>.from(resp.data as List);
} on DioError catch (e) {
if (e.type == DioErrorType.connectTimeout) throw Exception('Connection timed out');
if (e.response != null) throw Exception('Server error: ${e.response?.statusCode}');
throw Exception('Network error');
}
}Avoid returning raw response bodies across layers. Convert them into typed models before exposing to UI.
Interceptors And Advanced Configuration
Interceptors are where Dio shines for real apps. Use them to add auth tokens, handle 401 flows with refresh tokens, log requests, and perform retry logic. Register interceptors once on your Dio instance.
Authentication interceptor: attach bearer token to headers; on 401 attempt refresh then retry original request.
Logging interceptor: print concise request and response details in debug builds only.
Retry interceptor: perform limited retries for idempotent operations when transient network errors occur.
Example interceptor usage pattern:
onRequest: add auth header
onError: if statusCode is 401, pause, refresh token, retry
onResponse: optional centralized parsing or logging
Keep long running or blocking operations out of interceptors and use async-safe refresh mechanisms. Ensure retry loops have limits to prevent infinite recursion.
Parsing Responses And Models
Convert JSON into Dart models using factory constructors fromJson. Prefer immutability and explicit parsing to catch schema changes early. When API responses include nested objects or optional fields, handle nullability and provide fallback values.
Small model example for a list item. Keep parsing logic small and testable.
class Item {
final int id;
final String title;
Item({required this.id, required this.title});
factory Item.fromJson(Map<String, dynamic> json) =>
Item(id: json['id'] as int, title: json['title'] as String);
}Map responses to models immediately after the request completes so the rest of the app works with typed objects. For large payloads consider streaming parsing or pagination to manage memory and responsiveness.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
Dio provides the capabilities needed for production grade API integration in Flutter mobile development: centralized configuration, interceptors, structured error handling, and flexible request options. Create a single configured instance, use interceptors for auth and logging, handle DioError cases explicitly, and map API responses to typed models. With these patterns you gain predictable network behavior, concise request code, and easier testing across the app.