feat: Implement ApiService with Dio for standardized API requests and responses using ApiResponse entity.
This commit is contained in:
@@ -8,3 +8,4 @@ export 'src/presentation/mixins/bloc_error_handler.dart';
|
||||
export 'src/presentation/observers/core_bloc_observer.dart';
|
||||
export 'src/config/app_config.dart';
|
||||
export 'src/routing/routing.dart';
|
||||
export 'src/services/api_service.dart';
|
||||
|
||||
135
apps/mobile/packages/core/lib/src/services/api_service.dart
Normal file
135
apps/mobile/packages/core/lib/src/services/api_service.dart
Normal file
@@ -0,0 +1,135 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
/// A service that handles HTTP communication using the [Dio] client.
|
||||
///
|
||||
/// This class provides a wrapper around [Dio]'s methods to handle
|
||||
/// response parsing and error handling in a consistent way.
|
||||
class ApiService {
|
||||
/// Creates an [ApiService] with the given [Dio] instance.
|
||||
ApiService(this._dio);
|
||||
|
||||
/// The underlying [Dio] client used for network requests.
|
||||
final Dio _dio;
|
||||
|
||||
/// Performs a GET request to the specified [endpoint].
|
||||
Future<ApiResponse> get(
|
||||
String endpoint, {
|
||||
Map<String, dynamic>? params,
|
||||
}) async {
|
||||
try {
|
||||
final Response<dynamic> response = await _dio.get<dynamic>(
|
||||
endpoint,
|
||||
queryParameters: params,
|
||||
);
|
||||
return _handleResponse(response);
|
||||
} on DioException catch (e) {
|
||||
return _handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a POST request to the specified [endpoint].
|
||||
Future<ApiResponse> post(
|
||||
String endpoint, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? params,
|
||||
}) async {
|
||||
try {
|
||||
final Response<dynamic> response = await _dio.post<dynamic>(
|
||||
endpoint,
|
||||
data: data,
|
||||
queryParameters: params,
|
||||
);
|
||||
return _handleResponse(response);
|
||||
} on DioException catch (e) {
|
||||
return _handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a PUT request to the specified [endpoint].
|
||||
Future<ApiResponse> put(
|
||||
String endpoint, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? params,
|
||||
}) async {
|
||||
try {
|
||||
final Response<dynamic> response = await _dio.put<dynamic>(
|
||||
endpoint,
|
||||
data: data,
|
||||
queryParameters: params,
|
||||
);
|
||||
return _handleResponse(response);
|
||||
} on DioException catch (e) {
|
||||
return _handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a PATCH request to the specified [endpoint].
|
||||
Future<ApiResponse> patch(
|
||||
String endpoint, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? params,
|
||||
}) async {
|
||||
try {
|
||||
final Response<dynamic> response = await _dio.patch<dynamic>(
|
||||
endpoint,
|
||||
data: data,
|
||||
queryParameters: params,
|
||||
);
|
||||
return _handleResponse(response);
|
||||
} on DioException catch (e) {
|
||||
return _handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts [ApiResponse] from a successful [Response].
|
||||
ApiResponse _handleResponse(Response<dynamic> response) {
|
||||
if (response.data is Map<String, dynamic>) {
|
||||
final Map<String, dynamic> body = response.data as Map<String, dynamic>;
|
||||
return ApiResponse(
|
||||
code:
|
||||
body['code']?.toString() ??
|
||||
response.statusCode?.toString() ??
|
||||
'unknown',
|
||||
message: body['message']?.toString() ?? 'Success',
|
||||
data: body['data'],
|
||||
errors: _parseErrors(body['errors']),
|
||||
);
|
||||
}
|
||||
return ApiResponse(
|
||||
code: response.statusCode?.toString() ?? '200',
|
||||
message: 'Success',
|
||||
data: response.data,
|
||||
);
|
||||
}
|
||||
|
||||
/// Extracts [ApiResponse] from a [DioException].
|
||||
ApiResponse _handleError(DioException e) {
|
||||
if (e.response?.data is Map<String, dynamic>) {
|
||||
final Map<String, dynamic> body =
|
||||
e.response!.data as Map<String, dynamic>;
|
||||
return ApiResponse(
|
||||
code:
|
||||
body['code']?.toString() ??
|
||||
e.response?.statusCode?.toString() ??
|
||||
'error',
|
||||
message: body['message']?.toString() ?? e.message ?? 'Error occurred',
|
||||
data: body['data'],
|
||||
errors: _parseErrors(body['errors']),
|
||||
);
|
||||
}
|
||||
return ApiResponse(
|
||||
code: e.response?.statusCode?.toString() ?? 'error',
|
||||
message: e.message ?? 'Unknown error',
|
||||
errors: <String, dynamic>{'exception': e.type.toString()},
|
||||
);
|
||||
}
|
||||
|
||||
/// Helper to parse the errors map from various possible formats.
|
||||
Map<String, dynamic> _parseErrors(dynamic errors) {
|
||||
if (errors is Map) {
|
||||
return Map<String, dynamic>.from(errors);
|
||||
}
|
||||
return const <String, dynamic>{};
|
||||
}
|
||||
}
|
||||
@@ -21,3 +21,4 @@ dependencies:
|
||||
flutter_bloc: ^8.1.0
|
||||
equatable: ^2.0.8
|
||||
flutter_modular: ^6.4.1
|
||||
dio: ^5.9.1
|
||||
|
||||
Reference in New Issue
Block a user