ApiClient constructor
ApiClient(
- String initialBaseUrl
Implementation
ApiClient(String initialBaseUrl) {
_baseUrl = initialBaseUrl; // Set initial base URL
_dio = Dio(BaseOptions(
baseUrl: _baseUrl,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
connectTimeout: const Duration(seconds: 45),
receiveTimeout: const Duration(seconds: 45),
));
// Use platform-specific HttpClientAdapter
// _dio.httpClientAdapter = getHttpClientAdapter();
_dio.interceptors.add(ApiMonitorInterceptor());
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
final token = storageUtils.getToken();
final roleId = storageUtils.getRoleId() ?? '0';
final masterRoleTypeId = storageUtils.getMasterRoleTypeId() ?? '0';
final aclPositionMappingId = storageUtils.getAclPositionMapping() ?? '0';
if (token != null) {
options.headers['Authorization'] = token;
// options.headers['Authorization'] = '$token*##*$roleId*##*$masterRoleTypeId*##*$aclPositionMappingId*##*';
}
if (kDebugMode) {
logger.i('Request: ${options.method} ${options.uri}');
if (options.headers.isNotEmpty) {
logger.d('Headers: ${jsonEncode(options.headers)}');
}
if (options.queryParameters.isNotEmpty) {
logger.d('Query Parameters: ${options.queryParameters}');
}
if (options.data != null) {
logger.d('Request Body: ${options.data}');
}
}
return handler.next(options); //continue
},
onResponse: (response, handler) {
if (kDebugMode) {
logger.w('Response: ${jsonEncode(response.data)}');
}
return handler.next(response); // continue
},
onError: (DioException error, handler) {
final apiName = error.requestOptions.uri.toString(); // Extract API name
final userFriendlyMessage = ErrorParser.parseErrorMessage(error);
// Safe logging that won't crash on HTML response or null data
String errorPayload;
try {
if (error.response?.data != null) {
errorPayload = error.response!.data is String
? error.response!.data.toString()
: jsonEncode(error.response!.data);
} else {
errorPayload = error.message ?? 'No additional details';
}
} catch (_) {
errorPayload = 'Unencodable response data';
}
logger.e('\x1B[31m[ERROR] API: $apiName - Status: ${error.response?.statusCode} - $errorPayload\x1B[0m');
if (error.response != null) {
final statusCode = error.response?.statusCode;
switch (statusCode) {
case 401: // Unauthorized
break;
case 403: // Forbidden
_handleInvalidToken(userFriendlyMessage);
break;
case 440: // Login Timeout (non-standard)
_handleSessionExpired();
break;
case 400: // Bad Request
break;
case 404: // Not Found
break;
case 500: // Internal Server Error
case 502: // Bad Gateway
case 503: // Service Unavailable
case 504: // Gateway Timeout
// AppUtils.showSnackBar(userFriendlyMessage);
break;
default:
print('\x1B[31mUnhandled status code: $statusCode - $userFriendlyMessage\x1B[0m');
AppUtils.showSnackBar(userFriendlyMessage);
break;
}
} else {
// No response (timeout, offline, socket exception, etc.)
print('\x1B[31mNetwork error: ${error.message} - $userFriendlyMessage\x1B[0m');
AppUtils.showSnackBar(userFriendlyMessage);
}
// Return the modified error with copyWith to carry our clean message!
// This ensures existing code catching DioException receives the userFriendlyMessage
// without breaking the catch block types!
final updatedError = error.copyWith(message: userFriendlyMessage);
return handler.next(updatedError);
},
));
}