Files
minhthu/lib/core/network/api_client.dart
2025-09-16 23:14:35 +07:00

175 lines
4.8 KiB
Dart

import 'package:dio/dio.dart';
import '../constants/app_constants.dart';
import '../errors/exceptions.dart';
/// API client for making HTTP requests using Dio
class ApiClient {
late final Dio _dio;
ApiClient() {
_dio = Dio(
BaseOptions(
baseUrl: AppConstants.apiBaseUrl,
connectTimeout: const Duration(milliseconds: AppConstants.connectionTimeout),
receiveTimeout: const Duration(milliseconds: AppConstants.receiveTimeout),
sendTimeout: const Duration(milliseconds: AppConstants.sendTimeout),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
),
);
// Add request/response interceptors for logging and error handling
_dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
// Log request details in debug mode
handler.next(options);
},
onResponse: (response, handler) {
// Log response details in debug mode
handler.next(response);
},
onError: (error, handler) {
// Handle different types of errors
_handleDioError(error);
handler.next(error);
},
),
);
}
/// Make a GET request
Future<Response<T>> get<T>(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
return await _dio.get<T>(
path,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Make a POST request
Future<Response<T>> post<T>(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
return await _dio.post<T>(
path,
data: data,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Make a PUT request
Future<Response<T>> put<T>(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
return await _dio.put<T>(
path,
data: data,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Make a DELETE request
Future<Response<T>> delete<T>(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
return await _dio.delete<T>(
path,
data: data,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Handle Dio errors and convert them to custom exceptions
Exception _handleDioError(DioException error) {
switch (error.type) {
case DioExceptionType.connectionTimeout:
case DioExceptionType.sendTimeout:
case DioExceptionType.receiveTimeout:
return const NetworkException('Connection timeout. Please check your internet connection.');
case DioExceptionType.badResponse:
final statusCode = error.response?.statusCode;
final message = error.response?.data?['message'] ?? 'Server error occurred';
if (statusCode != null) {
if (statusCode >= 400 && statusCode < 500) {
return ServerException('Client error: $message (Status: $statusCode)');
} else if (statusCode >= 500) {
return ServerException('Server error: $message (Status: $statusCode)');
}
}
return ServerException('HTTP error: $message');
case DioExceptionType.cancel:
return const NetworkException('Request was cancelled');
case DioExceptionType.connectionError:
return const NetworkException('No internet connection. Please check your network settings.');
case DioExceptionType.badCertificate:
return const NetworkException('Certificate verification failed');
case DioExceptionType.unknown:
default:
return ServerException('An unexpected error occurred: ${error.message}');
}
}
/// Add authorization header
void addAuthorizationHeader(String token) {
_dio.options.headers['Authorization'] = 'Bearer $token';
}
/// Remove authorization header
void removeAuthorizationHeader() {
_dio.options.headers.remove('Authorization');
}
/// Update base URL (useful for different environments)
void updateBaseUrl(String newBaseUrl) {
_dio.options.baseUrl = newBaseUrl;
}
}