advanced_api_client 1.0.1
advanced_api_client: ^1.0.1 copied to clipboard
Production-ready Flutter/Dart API client built on Dio with authentication, automatic token refresh, retry interceptor, file uploads, global error handling, and clean architecture.
Advanced API Client #
A powerful, production-ready Flutter/Dart HTTP client built on top of dio.
advanced_api_client simplifies REST API integration with built-in:
- Authentication handling
- Automatic token refresh
- Retry mechanism
- File uploads
- Pagination support
- Global error handling
- Custom interceptors
- Session termination
- Clean architecture
Designed for scalability and real-world production apps.
โจ Features #
- โ GET, POST, PUT, PATCH, DELETE
- ๐ Token-based authentication
- ๐ Automatic token refresh (401 handling)
- โป๏ธ Retry interceptor (connection errors + timeout support)
- ๐ค Single & multiple file uploads
- ๐ฆ Pagination-ready
- ๐งฉ Custom interceptor support
- ๐ Global error callback
- ๐ช Session termination support
- ๐งช Works with Flutter & pure Dart
- ๐ Dynamic refresh token bodyBuilder support for passing runtime data (e.g., user_id from SharedPreferences)
- ๐ก Safe retry after token refresh for file uploads
๐ฆ Installation #
Add this to your pubspec.yaml:
dependencies:
advanced_api_client: ^1.0.1
Then run:
flutter pub get
๐ Getting Started #
1๏ธโฃ Initialize (Recommended โ Pre-init in main()) #
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await AdvancedApiClient.initialize(
config: ApiConfig(
baseUrl: "https://api.example.com",
refreshConfig: RefreshConfig(
path: "/auth/refresh",
method: "POST",
// Use bodyBuilder for dynamic runtime body
bodyBuilder: () async {
final prefs = await SharedPreferences.getInstance();
final userId = prefs.getString("user_id") ?? "";
return {"user_id": userId, "from_source": 1};
},
// or use body for static data
body: {
"from_source": 1
},
tokenParser: (data) => data["access_token"],
headers: {
"App-Version": "1.0.0",
"Platform": "Flutter",
},
),
),
);
runApp(MyApp());
}
Access anywhere:
final client = AdvancedApiClient.instance;
2๏ธโฃ Lazy Initialization (Optional) #
final client = await AdvancedApiClient.getInstance();
โ๏ธ ApiConfig #
The ApiConfig class allows you to configure the API client behavior.
class ApiConfig {
final String baseUrl;
final RefreshConfig? refreshConfig;
final List<Interceptor>? interceptors;
final void Function(DioException e, RequestOptions request)? onError;
final bool enableLogs;
const ApiConfig({
required this.baseUrl,
this.refreshConfig,
this.interceptors,
this.onError,
this.enableLogs = true,
});
}
๐น baseUrl (Required) #
Base URL of your API.
ApiConfig(
baseUrl: "https://api.example.com",
);
๐น refreshConfig (Optional) #
Used to automatically refresh access tokens when a 401 response is received.
Example:
ApiConfig(
baseUrl: "https://api.example.com",
refreshConfig: RefreshConfig(
path: "/auth/refresh",
method: "POST",
// Dynamic runtime body
bodyBuilder: () async {
final prefs = await SharedPreferences.getInstance();
final userId = prefs.getString("user_id") ?? "";
return {"user_id": userId, "from_source": 1};
},
// Static body
body: {"from_source": 1}
tokenParser: (data) => data["access_token"],
),
);
๐น interceptors (Optional) #
Add custom dio interceptors.
ApiConfig(
baseUrl: "https://api.example.com",
interceptors: [
LogInterceptor(responseBody: true),
],
);
๐น onError (Optional) #
Global error callback triggered for all request errors.
ApiConfig(
baseUrl: "https://api.example.com",
onError: (DioException e, RequestOptions request) async {
final statusCode = e.response?.statusCode;
if (statusCode == 401) {
await AdvancedApiClient.instance.terminateSession();
}
if (statusCode == 500) {
debugPrint("Server error occurred");
}
if (e.type == DioExceptionType.connectionError) {
debugPrint("No internet connection");
}
},
);
๐ Basic Requests #
GET #
await client.get(
endpoint: "/users",
headers: {"X-Custom-Header": "12345"},
);
POST #
await client.post(
endpoint: "/users",
body: {"name": "John"},
headers: {"X-Custom-Header": "12345"},
);
PUT #
await client.put(
endpoint: "/users/1",
body: {"name": "Updated"},
headers: {"X-Custom-Header": "12345"},
);
PATCH #
await client.patch(
endpoint: "/users/1",
body: {"status": "active"},
headers: {"X-Custom-Header": "12345"},
);
DELETE #
await client.delete(endpoint: "/users/1");
๐ค File Upload Examples #
final client = AdvancedApiClient.instance;
Upload Single File #
await client.upload(
endpoint: "/common/file-upload/image",
files: {
"image": [pickedFile.path],
},
headers: {"X-Custom-Header": "12345"},
);
Upload Multiple Files (Same Field) #
await client.upload(
endpoint: "/common/file-upload/image",
files: {
"image": filePaths, // List<String>
},
headers: {"X-Custom-Header": "12345"},
);
Upload Multiple Files (Different Fields) #
await client.upload(
endpoint: "/upload",
files: {
"profile_image": [profilePath],
"documents": documentPaths,
},
fields: {
"user_id": 1,
"type": "verification",
},
headers: {"X-Custom-Header": "12345"},
);
๐ช Terminate Session #
Clears tokens and cancels all pending requests:
await AdvancedApiClient.instance.terminateSession();
๐ Retry Mechanism #
Built-in retry interceptor supports:
- Connection errors
- Receive timeout
- Configurable retry attempts
- Optional exponential backoff
Helps reduce random network failures in production.
๐ Architecture #
AdvancedApiClient
โโโ AuthInterceptor
โโโ RetryInterceptor
โโโ TokenStorage
โโโ ApiConfig
โโโ RefreshConfig (supports bodyBuilder)
โโโ ApiException
Clean separation of concerns and extensibility.
๐งช Works With #
- Flutter Mobile
- Flutter Web
- Flutter Desktop
- Pure Dart projects
๐ License #
MIT License ยฉ 2026
โค๏ธ Why Advanced API Client? #
Because production apps need more than just dio.
You get:
- Cleaner codebase
- Centralized API management
- Safer authentication flow
- Easier scaling
- Better maintainability