networking_layer 1.0.1
networking_layer: ^1.0.1 copied to clipboard
A robust, solid-compliant networking layer using Dio.
Networking Layer #
A robust, SOLID-compliant networking package for Flutter using Dio.
Features #
- Decoupled Architecture: Independent of app-specific logic using
DioConfig. - SOLID Principles: Clean separation of concerns.
- Interceptors: Built-in support for Logging, Auth, Caching, and Retries.
- GraphQL & REST: Unified
ApiClientmixin for both. - Error Handling: Standardized
HelperResponsewith functional error handling (Either). - File Handling: Easy Upload and Download methods.
Arabic Tutorial / شرح بالعربي: You can find a detailed explanation script in Arabic here: شرح مفصل للباكج
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
networking_layer:
# If using locally
path: ./packages/networking_layer
# OR if using git
# git:
# url: https://github.com/your_username/networking_layer.git
Usage #
1. Initialization #
Initialize DioServices in your main.dart or startup logic. You need to provide a DioConfig object.
void main() {
DioServices.instance.init(
DioConfig(
baseUrl: 'https://api.example.com',
getToken: () {
// Return your auth token here
return 'your_token';
},
translate: (key) {
// Implement your translation logic here (e.g., using easy_localization)
// return context.tr(key);
return key;
},
onTokenExpired: () {
// Handle 401 errors (e.g., logout user)
print('Token expired! Logging out...');
},
onConnectionError: () {
// Handle connection errors globally
print('No internet connection!');
},
),
);
runApp(MyApp());
}
2. Creating a Repository #
Use the ApiClient mixin in your repository classes to access networking methods.
class UserRepository with ApiClient {
// 🟦 REST GET Example
Future<Either<HelperResponse, User>> getUser(String id) async {
return await get<User>(
'/users/$id',
fromJson: (json) => User.fromJson(json),
);
}
// 🟩 REST POST Example
Future<Either<HelperResponse, User>> createUser(User user) async {
return await post<User>(
'/users',
data: user.toJson(),
fromJson: (json) => User.fromJson(json),
);
}
// 🟪 GraphQL Query Example
Future<Either<HelperResponse, User>> getUserGraphQL(String id) async {
const query = '''
query GetUser($id: ID!) {
user(id: $id) {
id
name
}
}
''';
return await graphQLQuery<User>(
query,
variables: {'id': id},
fromJson: (json) => User.fromJson(json),
dataKey: 'user', // Extract 'user' object from data
);
}
}
3. Handling Responses #
The methods return Either<HelperResponse, T>. Use .fold to handle success and failure.
final repository = UserRepository();
final result = await repository.getUser('123');
result.fold(
(error) {
// ❌ Handle Error
print('Error: ${error.message}');
print('Status Code: ${error.statusCode}');
},
(user) {
// ✅ Handle Success
print('User: ${user.name}');
},
);
Advanced Usage #
File Upload #
Future<Either<HelperResponse, String>> uploadAvatar(File image) async {
return await upload<String>(
'/upload',
formData: {
'file': await MultipartFile.fromFile(image.path),
'type': 'avatar',
},
fromJson: (json) => json['url'],
);
}
File Download #
Future<Either<HelperResponse, String>> downloadFile(String url) async {
return await download(
url,
'/save/path/file.pdf',
onReceiveProgress: (received, total) {
print('Progress: ${(received / total * 100).toStringAsFixed(0)}%');
},
);
}
Error Handling #
HelperResponse provides a unified way to handle errors. Common states include:
ResponseState.successResponseState.noInternetResponseState.unauthorizedResponseState.serverErrorResponseState.badRequest
You can also use helper getters like error.isNetworkError, error.isAuthError, etc. (if implemented in HelperResponse, otherwise check state).