Files
mobile-app/lib/core/network/api_client.dart

93 lines
2.5 KiB
Dart

import 'package:dio/dio.dart';
import 'package:real_estate_mobile/config/app_config.dart';
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
import 'package:real_estate_mobile/core/storage/secure_storage.dart';
class ApiClient {
static ApiClient? _instance;
late final Dio _dio;
ApiClient._() {
_dio = Dio(
BaseOptions(
baseUrl: AppConfig.apiBaseUrl,
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
),
);
_dio.interceptors.addAll([
_authInterceptor(),
_errorInterceptor(),
]);
}
static ApiClient get instance {
_instance ??= ApiClient._();
return _instance!;
}
Dio get dio => _dio;
InterceptorsWrapper _authInterceptor() {
return InterceptorsWrapper(
onRequest: (options, handler) async {
final token = await SecureStorage.getAccessToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
},
);
}
InterceptorsWrapper _errorInterceptor() {
return InterceptorsWrapper(
onError: (error, handler) {
final response = error.response;
if (response != null) {
final data = response.data;
if (data is Map<String, dynamic>) {
final message = data['message'] is List
? (data['message'] as List).join(', ')
: data['message']?.toString() ?? 'An error occurred';
final errors = (data['errors'] as List<dynamic>?)
?.map((e) => FieldError.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
handler.reject(
DioException(
requestOptions: error.requestOptions,
response: error.response,
error: ApiException(
message: message,
statusCode: response.statusCode,
fieldErrors: errors,
),
),
);
return;
}
}
handler.reject(
DioException(
requestOptions: error.requestOptions,
response: error.response,
error: ApiException(
message: error.message ?? 'Network error occurred',
statusCode: response?.statusCode,
),
),
);
},
);
}
}