fast_dio 1.0.0
fast_dio: ^1.0.0 copied to clipboard
Dio-based HTTP layer with the same API surface as fast_http — GenericRequest, headers, errors, download, stream, and interceptors.
fast_dio #
Dio-based HTTP client for Flutter with the same developer experience as fast_http.
It provides a typed request layer (GenericRequest), global headers, structured errors, multipart uploads, query parameters, download/stream support, and Dio interceptors — without exposing low-level Dio setup in every feature.
Features #
- Same API pattern as
fast_http:FastDio,FastDioHeader,RequestApi,GenericRequest - JSON parsing with
getObject,getList,getResponse,getBytes - Global and per-request headers (static + async dynamic headers)
- Centralized error handling with
ServerExceptionandRequestErrorModel - Status-code hooks for auth flows (401, 406, etc.)
- Query parameters support
- Multipart uploads with named fields via
RequestFile - Per-request Dio options: timeouts,
CancelToken, progress callbacks - File download and streamed responses
- Interceptor helpers and built-in logging support
- Optional Chucker Flutter inspector (
useChucker) for in-app request/response UI - Exports
fpdartfor functional error handling
Getting started #
Add the dependency:
dependencies:
fast_dio: ^1.0.0
Or from GitHub:
dependencies:
fast_dio:
git:
url: https://github.com/El-sayed-mahmoud/fast_dio.git
Usage #
Initialize #
import 'package:fast_dio/fast_dio.dart';
void setupHttp() {
FastDio.initialize(
genericDataKey: 'data',
checkStatusKey: 'status',
checkResponseIsSuccess: (response) => true,
getErrorMessageFromResponse: (response) {
return response['message']?.toString() ?? 'An error occurred';
},
onGetResponseStatusCode: (statusCode) {
if (statusCode == 401) {
// handle logout / redirect
}
},
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 60),
);
FastDioHeader().addHeader('Accept', '*/*');
FastDioHeader().addHeader('content-type', 'application/json');
FastDioHeader().addDynamicHeader(
'Authorization',
() async => 'Bearer YOUR_TOKEN',
);
FastDio.addLogInterceptor(responseBody: true);
}
Chucker inspector (on-device) #
Enable in-app request/response inspection while testing on a real device or emulator:
import 'package:chucker_flutter/chucker_flutter.dart';
import 'package:fast_dio/fast_dio.dart';
import 'package:flutter/foundation.dart';
void setupHttp() {
FastDio.initialize(
onGetResponseStatusCode: (statusCode) {},
useChucker: kDebugMode,
);
}
// In MaterialApp — required for Chucker notifications and screens:
MaterialApp(
navigatorKey: ChuckerFlutter.navigatorKey,
home: const HomePage(),
);
Or add manually:
FastDio.addChuckerInterceptor();
Notes:
useChuckertakes precedence overusePrettyLoggerwhen both aretrue.- On Android, set
minSdkVersionto at least22. - Chucker runs in debug mode by default; set
ChuckerFlutter.showOnRelease = trueonly if you need it in release builds.
GET object #
final request = GenericRequest<UserModel>(
fromMap: UserModel.fromJson,
method: RequestApi.get(
url: 'https://api.example.com/user/1',
queryParameters: {'lang': 'ar'},
),
);
final user = await request.getObject();
POST with body #
final request = GenericRequest<LoginResponse>(
fromMap: LoginResponse.fromJson,
method: RequestApi.post(
url: 'https://api.example.com/login',
body: {'email': email, 'password': password},
),
);
final response = await request.getObject();
Upload file #
await RequestApi.post(
url: 'https://api.example.com/upload',
body: {'title': 'avatar'},
isMultipartRequest: true,
files: [
RequestFile(
field: 'file',
file: await MultipartFile.fromFile(path, filename: 'avatar.jpg'),
),
],
).request();
Download file #
final path = await RequestApi.get(
url: 'https://api.example.com/report.pdf',
).download(savePath: '/path/to/report.pdf');
Stream response #
final body = await RequestApi.get(
url: 'https://api.example.com/stream',
).requestStream();
final stream = body.stream;
Progress #
FastDio.progressUpdates.listen((progress) {
print('${progress.direction}: ${progress.percentage}%');
});
Example #
A minimal end-to-end setup with Chucker in debug mode and a typed GET request:
import 'package:fast_dio/fast_dio.dart' hide State;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
setupHttp();
runApp(const MyApp());
}
void setupHttp() {
FastDio.initialize(
genericDataKey: 'data',
checkStatusKey: 'status',
checkResponseIsSuccess: (response) => response['status'] == true,
getErrorMessageFromResponse: (response) {
return response['message']?.toString() ?? 'An error occurred';
},
onGetResponseStatusCode: (statusCode) {
if (statusCode == 401) {
// handle logout / redirect
}
},
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 60),
useChucker: kDebugMode,
);
FastDioHeader().addHeader('Accept', 'application/json');
FastDioHeader().addDynamicHeader(
'Authorization',
() async => 'Bearer YOUR_TOKEN',
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: ChuckerFlutter.navigatorKey,
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String _result = 'Tap the button to load a user';
Future<void> _loadUser() async {
try {
final request = GenericRequest<UserModel>(
fromMap: UserModel.fromJson,
method: RequestApi.get(
url: 'https://jsonplaceholder.typicode.com/users/1',
),
);
final user = await request.getResponse();
setState(() => _result = '${user.name} (${user.email})');
} on ServerException catch (e) {
setState(() => _result = e.errorMessageModel.statusMessage);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('fast_dio example')),
body: Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_result, textAlign: TextAlign.center),
const SizedBox(height: 16),
FilledButton(
onPressed: _loadUser,
child: const Text('Load user'),
),
],
),
),
),
);
}
}
class UserModel {
const UserModel({required this.name, required this.email});
final String name;
final String email;
factory UserModel.fromJson(dynamic json) {
return UserModel(
name: json['name']?.toString() ?? '',
email: json['email']?.toString() ?? '',
);
}
}
Run the sample app from the package repo:
cd example
flutter pub get
flutter run
Repository with fpdart (Either) #
static Future<Either<Failure, UserModel>> getUserData({String? userId}) async {
try {
// profileUrl / userUrl are your own endpoint builders
final url = userId == currentUserId ? profileUrl : userUrl(userId: userId);
UserModel response = await GenericRequest<UserModel>(
method: RequestApi.get(url: url),
fromMap: UserModel.fromJson,
).getObject();
return Right(response);
} on ServerException catch (failure) {
return Left(ServerFailure(failure.errorMessageModel));
}
}
static Future<Either<Failure, List<UserModel>>> getUserList() async {
try {
List<UserModel> response = await GenericRequest<UserModel>(
method: RequestApi.get(url: usersListUrl),
fromMap: UserModel.fromJson,
).getList();
return Right(response);
} on ServerException catch (failure) {
return Left(ServerFailure(failure.errorMessageModel));
}
}
static Future<Either<Failure, bool>> logout() async {
try {
bool response = await GenericRequest<bool>(
method: RequestApi.get(url: logoutUrl),
fromMap: (_) => true,
).getObject();
return Right(response);
} on ServerException catch (failure) {
return Left(ServerFailure(failure.errorMessageModel));
}
}
result.fold(
(failure) => showError(failure.errorModel.statusMessage),
(user) => showProfile(user),
);
API overview #
| fast_http | fast_dio |
|---|---|
FastHttp |
FastDio |
FastHttpHeader |
FastDioHeader |
RequestApi |
RequestApi |
GenericRequest |
GenericRequest |
dartz export |
fpdart export |
Additional information #
- Source code: GitHub
- Issues: GitHub Issues