installNetworkModule function
Implementation
Future<void> installNetworkModule(String projectPath) async {
final flutterCmd = Platform.isWindows ? 'flutter.bat' : 'flutter';
print('📦 Installing network dependencies...');
await Process.run(
flutterCmd,
['pub', 'add', 'dio', 'pretty_dio_logger', 'connectivity_plus'],
workingDirectory: projectPath,
runInShell: true,
);
final networkDirPath = p.join(projectPath, 'lib', 'core', 'network');
safeCreateDir(networkDirPath);
// ==========================
// app_config.dart
// ==========================
final configDir = Directory(
p.join(projectPath, 'lib', 'core', 'config'),
);
configDir.createSync(recursive: true);
safeWriteFile(p.join(configDir.path, 'app_config.dart'),'''
class AppConfig {
static late String baseUrl;
static void initialize(String flavor) {
switch (flavor) {
case "dev":
baseUrl = "https://dev-api.example.com";
break;
case "prod":
baseUrl = "https://api.example.com";
break;
default:
baseUrl = "https://dev-api.example.com";
}
}
}
''');
// ==========================
// api_service.dart
// ==========================
final servicesDir = Directory(
p.join(projectPath, 'lib', 'core', 'services'),
);
servicesDir.createSync(recursive: true);
safeWriteFile(p.join(servicesDir.path, 'api_service.dart'),'''
import '../config/app_config.dart';
import '../network/api_client.dart';
class ApiService {
static final ApiClient client =
ApiClient(AppConfig.baseUrl);
}
''');
// ==========================
// api_client.dart
// ==========================
safeWriteFile(p.join(networkDirPath, 'api_client.dart'),'''
import 'package:dio/dio.dart';
import 'api_interceptor.dart';
import 'api_response.dart';
import 'api_exception.dart';
class ApiClient {
late final Dio _dio;
ApiClient(String baseUrl) {
_dio = Dio(
BaseOptions(
baseUrl: baseUrl,
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
headers: {
"Content-Type": "application/json",
},
),
);
_dio.interceptors.add(ApiInterceptor());
}
Future<ApiResponse> get(String path,{Map<String,dynamic>? query}) async {
try {
final response = await _dio.get(
path,
queryParameters: query,
);
return ApiResponse.success(response.data);
} catch (e) {
if(e is DioException && e.error is ApiException){
return ApiResponse.error(e.error.toString());
}
return ApiResponse.error("Unexpected error occurred");
}
}
Future<ApiResponse> post(String path,{dynamic data}) async {
try {
final response = await _dio.post(
path,
data: data,
);
return ApiResponse.success(response.data);
} catch (e) {
if(e is DioException && e.error is ApiException){
return ApiResponse.error(e.error.toString());
}
return ApiResponse.error("Unexpected error occurred");
}
}
Future<ApiResponse> put(String path,{dynamic data}) async {
try {
final response = await _dio.put(
path,
data: data,
);
return ApiResponse.success(response.data);
} catch (e) {
if(e is DioException && e.error is ApiException){
return ApiResponse.error(e.error.toString());
}
return ApiResponse.error("Unexpected error occurred");
}
}
Future<ApiResponse> delete(String path) async {
try {
final response = await _dio.delete(path);
return ApiResponse.success(response.data);
} catch (e) {
if(e is DioException && e.error is ApiException){
return ApiResponse.error(e.error.toString());
}
return ApiResponse.error("Unexpected error occurred");
}
}
Future<ApiResponse> multipart(
String path,
Map<String,dynamic> fields,
Map<String,MultipartFile> files,
) async {
try {
final formData = FormData.fromMap({
...fields,
...files,
});
final response = await _dio.post(
path,
data: formData,
options: Options(contentType: "multipart/form-data"),
);
return ApiResponse.success(response.data);
} catch (e) {
if(e is DioException && e.error is ApiException){
return ApiResponse.error(e.error.toString());
}
return ApiResponse.error("Unexpected error occurred");
}
}
void setToken(String token){
_dio.options.headers["Authorization"] = "Bearer \$token";
}
}
''');
// ==========================
// api_endpoints.dart
// ==========================
safeWriteFile(p.join(networkDirPath, 'api_endpoints.dart'),'''
class ApiEndpoints {
static const String login = "/login";
static const String signup = "/signup";
static const String profile = "/profile";
}
''');
// ==========================
// api_exception.dart
// ==========================
safeWriteFile(p.join(networkDirPath, 'api_exception.dart'),'''
class ApiException implements Exception {
final String message;
ApiException(this.message);
@override
String toString() => message;
}
''');
// ==========================
// api_response.dart
// ==========================
safeWriteFile(p.join(networkDirPath, 'api_response.dart'),'''
class ApiResponse<T> {
final T? data;
final String? message;
final bool success;
ApiResponse({
this.data,
this.message,
this.success = true,
});
factory ApiResponse.success(T data) {
return ApiResponse(
data: data,
success: true,
);
}
factory ApiResponse.error(String message) {
return ApiResponse(
message: message,
success: false,
);
}
}
''');
// ==========================
// api_interceptor.dart
// ==========================
safeWriteFile(p.join(networkDirPath, 'api_interceptor.dart'),'''
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'api_exception.dart';
class ApiInterceptor extends Interceptor {
final PrettyDioLogger _logger = PrettyDioLogger(
requestBody: true,
responseBody: true,
);
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
options.headers["Accept"] = "application/json";
_logger.onRequest(options, handler);
}
@override
void onResponse(
Response response,
ResponseInterceptorHandler handler,
) {
_logger.onResponse(response, handler);
}
@override
void onError(
DioException err,
ErrorInterceptorHandler handler,
) {
final message = _handleError(err);
handler.reject(
DioException(
requestOptions: err.requestOptions,
error: ApiException(message),
),
);
}
String _handleError(DioException error) {
final response = error.response;
final data = response?.data;
final serverMessage = _extractServerMessage(data);
if (serverMessage != null) {
return serverMessage;
}
switch (error.type) {
case DioExceptionType.connectionTimeout:
return "Connection timeout. Please try again.";
case DioExceptionType.sendTimeout:
return "Request timeout. Please try again.";
case DioExceptionType.receiveTimeout:
return "Server is taking too long to respond.";
case DioExceptionType.connectionError:
final msg = error.message ?? "";
if (msg.contains("SocketException")) {
return "No internet connection.";
}
return "Unable to reach server.";
case DioExceptionType.badResponse:
final statusCode = response?.statusCode;
switch (statusCode) {
case 400:
return "Invalid request.";
case 401:
return "Session expired. Please login again.";
case 403:
return "Access denied.";
case 404:
return "Requested resource not found.";
case 422:
return "Validation error.";
case 500:
return "Server error. Please try again later.";
default:
return "Something went wrong.";
}
case DioExceptionType.cancel:
return "Request cancelled.";
default:
return "Unexpected error occurred.";
}
}
String? _extractServerMessage(dynamic data) {
if (data == null) return null;
if (data is Map<String, dynamic>) {
if (data["message"] != null) {
return data["message"].toString();
}
if (data["error"] != null) {
return data["error"].toString();
}
if (data["detail"] != null) {
return data["detail"].toString();
}
if (data["errors"] != null) {
final errors = data["errors"];
if (errors is List && errors.isNotEmpty) {
return errors.first.toString();
}
if (errors is Map && errors.isNotEmpty) {
return errors.values.first.toString();
}
}
}
return null;
}
}
''');
// ==========================
// network_info.dart
// ==========================
safeWriteFile(p.join(networkDirPath, 'network_info.dart'),'''
import 'package:connectivity_plus/connectivity_plus.dart';
class NetworkInfo {
final Connectivity connectivity;
NetworkInfo(this.connectivity);
Future<bool> get isConnected async {
final result = await connectivity.checkConnectivity();
return result != ConnectivityResult.none;
}
}
''');
await _updateBootstrapForNetwork(projectPath);
print('🌐 Enterprise network module generated successfully.');
}