Files
CityCards_Customer_Flutter/lib/networkApiServices/network_api_services.dart
2026-01-12 12:48:59 +05:30

174 lines
5.3 KiB
Dart

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
class NetworkApiService {
static final NetworkApiService _instance = NetworkApiService._internal();
late Dio _dio;
factory NetworkApiService() {
return _instance;
}
NetworkApiService._internal() {
_dio = Dio(
BaseOptions(
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
),
);
// === RETRY INTERCEPTOR (for timeouts & connection errors) ===
_dio.interceptors.add(InterceptorsWrapper(
onError: (DioException err, handler) async {
final options = err.requestOptions;
const maxRetries = 2; // Total attempts = 1 initial + 2 retry
final currentRetry = options.extra['retry'] as int? ?? 0;
final shouldRetry = currentRetry < maxRetries &&
(err.type == DioExceptionType.connectionTimeout ||
err.type == DioExceptionType.sendTimeout ||
err.type == DioExceptionType.receiveTimeout );
if (shouldRetry) {
if (kDebugMode) {
print('🔁 Retrying request (${currentRetry + 1}) to ${options.uri}');
}
// Wait before retrying
// await Future.delayed(const Duration(seconds: 1));
options.extra['retry'] = currentRetry + 1;
// Re-execute the request
try {
final response = await _dio.fetch(options);
return handler.resolve(response);
} on DioException catch (e) {
return handler.reject(e);
}
}
// Not retrying → propagate original error
return handler.reject(err);
},
));
// === MAIN INTERCEPTOR (logging, auth, etc.) ===
_dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
// Add token if available (uncomment when needed)
// String? token = "your_token_here";
// if (token != null) {
// options.headers['Authorization'] = 'Bearer $token';
// }
if (kDebugMode) {
print('📤 REQUEST[${options.method}] => URL: ${options.uri}');
}
return handler.next(options);
},
onResponse: (response, handler) {
if (kDebugMode) {
print('📥 RESPONSE[${response.statusCode}] => DATA: ${response.data}');
}
return handler.next(response);
},
onError: (error, handler) {
if (kDebugMode) {
print('❌ ERROR[${error.response?.statusCode}] => MESSAGE: ${error.message}');
}
return handler.next(error);
},
),
);
// === DIO LOGGING INTERCEPTOR (debug only) ===
if (kDebugMode) {
_dio.interceptors.add(
LogInterceptor(
request: true,
requestHeader: true,
requestBody: true,
responseHeader: false,
responseBody: true,
error: true,
),
);
}
}
// GET API Request
Future<Response> getApi({
required String url,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
final response = await _dio.get(
url,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
);
return response;
} on DioException catch (e) {
throw _handleError(e);
}
}
// POST API Request
Future<Response> postApi({
required String url,
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
ProgressCallback? onSendProgress,
}) async {
try {
final response = await _dio.post(
url,
data: data,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
);
return response;
} on DioException catch (e) {
throw _handleError(e);
}
}
// Error Handler
String _handleError(DioException error) {
String errorDescription = "";
switch (error.type) {
case DioExceptionType.connectionTimeout:
errorDescription = "Connection timeout. Please try again.";
break;
case DioExceptionType.sendTimeout:
errorDescription = "Send timeout. Please try again.";
break;
case DioExceptionType.receiveTimeout:
errorDescription = "Receive timeout. Please try again.";
break;
case DioExceptionType.badCertificate:
errorDescription = "Bad certificate.";
break;
case DioExceptionType.badResponse:
errorDescription = error.response?.data['message'] ??
"Received invalid status code: ${error.response?.statusCode}";
break;
case DioExceptionType.cancel:
errorDescription = "Request was cancelled.";
break;
case DioExceptionType.connectionError:
errorDescription = "No internet connection.";
break;
case DioExceptionType.unknown:
errorDescription = "Something went wrong. Please try again.";
break;
}
return errorDescription;
}
// Update headers (e.g., add auth token)
void updateHeaders(Map<String, dynamic> headers) {
_dio.options.headers.addAll(headers);
}
}