feat:dio client done
This commit is contained in:
3
lib/core/constants/api_const.dart
Normal file
3
lib/core/constants/api_const.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
abstract class ApiConst {
|
||||
static const String baseUrl = "https://superapp.felixits.uz/api/v1";
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export 'app_locale_keys.dart';
|
||||
export 'sizes_consts.dart';
|
||||
export 'l10n.dart';
|
||||
export 'time_delay_cons.dart';
|
||||
export 'time_delay_cons.dart';
|
||||
export 'api_const.dart';
|
||||
@@ -2,6 +2,6 @@ abstract class TimeDelayConst {
|
||||
static const Duration durationMill150 = Duration(milliseconds: 150);
|
||||
static const Duration durationMill300 = Duration(milliseconds: 300);
|
||||
static const Duration durationMill800 = Duration(milliseconds: 800);
|
||||
|
||||
static const Duration durationMill3500 = Duration(milliseconds: 3500);
|
||||
static const Duration duration3 = Duration(seconds: 3);
|
||||
}
|
||||
|
||||
@@ -11,4 +11,6 @@ export 'l10n/app_localizations_en.dart';
|
||||
export 'l10n/app_localizations_ru.dart';
|
||||
export 'l10n/app_localizations_uz.dart';
|
||||
export 'services/services.dart';
|
||||
export 'utils/app_utils.dart';
|
||||
export 'utils/app_utils.dart';
|
||||
export 'exceptions/exceptions.dart';
|
||||
export 'exceptions/failure.dart';
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// coverage:ignore-file
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:dio/dio.dart' as _i361;
|
||||
import 'package:get_it/get_it.dart' as _i174;
|
||||
import 'package:injectable/injectable.dart' as _i526;
|
||||
|
||||
@@ -24,7 +25,9 @@ import '../../feature/main/presentation/blocs/main_bloc/main_bloc.dart'
|
||||
import '../../feature/on_boarding/presentation/blocs/splash_bloc/splash_bloc.dart'
|
||||
as _i311;
|
||||
import '../../food_delivery_client.dart' as _i321;
|
||||
import '../network/dio_client.dart' as _i667;
|
||||
import '../router/app_routes.dart' as _i152;
|
||||
import '../services/request_handler_service.dart' as _i354;
|
||||
import '../services/storage_service.dart' as _i306;
|
||||
|
||||
extension GetItInjectableX on _i174.GetIt {
|
||||
@@ -34,6 +37,7 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
_i526.EnvironmentFilter? environmentFilter,
|
||||
}) {
|
||||
final gh = _i526.GetItHelper(this, environment, environmentFilter);
|
||||
final dioModule = _$DioModule();
|
||||
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
|
||||
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
|
||||
gh.factory<_i991.BrowseBloc>(() => _i991.BrowseBloc());
|
||||
@@ -41,9 +45,16 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc());
|
||||
gh.singleton<_i306.StorageService>(() => _i306.StorageService());
|
||||
gh.singleton<_i152.AppRoutes>(() => _i152.AppRoutes());
|
||||
gh.lazySingleton<_i667.DioClient>(() => _i667.DioClient());
|
||||
gh.factory<_i942.LanguageBloc>(
|
||||
() => _i942.LanguageBloc(gh<_i321.StorageService>()),
|
||||
);
|
||||
gh.lazySingleton<_i361.Dio>(() => dioModule.dio(gh<_i667.DioClient>()));
|
||||
gh.singleton<_i354.RequestHandlerService>(
|
||||
() => _i354.RequestHandlerService(gh<_i361.Dio>()),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
class _$DioModule extends _i667.DioModule {}
|
||||
|
||||
32
lib/core/exceptions/exceptions.dart
Normal file
32
lib/core/exceptions/exceptions.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
class ServerException implements Exception {
|
||||
final String errorMessage;
|
||||
final String errorKey;
|
||||
final num statusCode;
|
||||
|
||||
const ServerException({
|
||||
required this.statusCode,
|
||||
required this.errorMessage,
|
||||
required this.errorKey,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ServerException(statusCode: $statusCode, errorMessage: $errorMessage, errorKey: $errorKey)';
|
||||
}
|
||||
}
|
||||
|
||||
class CustomDioException implements Exception {
|
||||
final String errorMessage;
|
||||
final DioExceptionType type;
|
||||
final int? statusCode;
|
||||
|
||||
CustomDioException({required this.errorMessage, required this.type, this.statusCode});
|
||||
}
|
||||
|
||||
class ParsingException implements Exception {
|
||||
final String errorMessage;
|
||||
|
||||
const ParsingException({required this.errorMessage});
|
||||
}
|
||||
44
lib/core/exceptions/failure.dart
Normal file
44
lib/core/exceptions/failure.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
class Failure extends Equatable {
|
||||
final String? errorMessage;
|
||||
final String? errorKey;
|
||||
|
||||
const Failure({
|
||||
this.errorMessage,
|
||||
this.errorKey,
|
||||
}); //error key kere bomasa required qilish shartamas
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
errorMessage,
|
||||
errorKey,
|
||||
];
|
||||
}
|
||||
|
||||
class ServerFailure extends Failure {
|
||||
final num statusCode;
|
||||
|
||||
const ServerFailure({
|
||||
required super.errorMessage,
|
||||
required this.statusCode,
|
||||
required super.errorKey,
|
||||
});
|
||||
}
|
||||
|
||||
class DioFailure extends Failure {
|
||||
final DioExceptionType type;
|
||||
final int? statusCode;
|
||||
|
||||
const DioFailure({
|
||||
required super.errorMessage,
|
||||
this.type = DioExceptionType.badResponse,
|
||||
this.statusCode,
|
||||
});
|
||||
}
|
||||
|
||||
class ParsingFailure extends Failure {
|
||||
const ParsingFailure({required super.errorMessage});
|
||||
}
|
||||
|
||||
class CacheFailure extends Failure {}
|
||||
44
lib/core/network/dio_client.dart
Normal file
44
lib/core/network/dio_client.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:food_delivery_client/core/network/header_interceptors.dart';
|
||||
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||
import 'error_handler_interceptor.dart';
|
||||
|
||||
@module
|
||||
abstract class DioModule {
|
||||
@lazySingleton
|
||||
Dio dio(DioClient dioClient) => dioClient.dio;
|
||||
}
|
||||
|
||||
@lazySingleton
|
||||
class DioClient {
|
||||
final BaseOptions _dioBaseOptions = BaseOptions(
|
||||
baseUrl: ApiConst.baseUrl,
|
||||
connectTimeout: TimeDelayConst.durationMill3500,
|
||||
receiveTimeout: TimeDelayConst.durationMill3500,
|
||||
followRedirects: false,
|
||||
validateStatus: (status) => status != null && status >= 200 && status < 300,
|
||||
);
|
||||
|
||||
Dio get dio {
|
||||
final Dio dio = Dio(_dioBaseOptions);
|
||||
dio.interceptors
|
||||
..add(HeaderInterceptors())
|
||||
..add(ErrorHandlerInterceptors())
|
||||
..add(
|
||||
LogInterceptor(
|
||||
requestHeader: true,
|
||||
requestBody: true,
|
||||
responseBody: true,
|
||||
error: true,
|
||||
request: true,
|
||||
logPrint: (object) {
|
||||
if (kDebugMode) {
|
||||
log('Error ${object.toString()}');
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
return dio;
|
||||
}
|
||||
}
|
||||
41
lib/core/network/error_handler_interceptor.dart
Normal file
41
lib/core/network/error_handler_interceptor.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../../feature/common/data/models/error_model.dart';
|
||||
|
||||
class ErrorHandlerInterceptors extends Interceptor {
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) {
|
||||
if (err.response != null && err.response!.statusCode != null) {
|
||||
if (err.response?.data is String) {
|
||||
final errorMessage = err.response?.data as String?;
|
||||
final error = ErrorModel(
|
||||
detail: errorMessage?.replaceAll(RegExp(r'<[^>]+>'), '') ?? '',
|
||||
);
|
||||
handler.next(
|
||||
DioException(
|
||||
requestOptions: err.requestOptions,
|
||||
response: Response(
|
||||
requestOptions: err.requestOptions,
|
||||
data: error.toJson(),
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
handler.next(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const error = ErrorModel(detail: "");
|
||||
handler.next(
|
||||
DioException(
|
||||
requestOptions: err.requestOptions,
|
||||
response: Response(
|
||||
requestOptions: err.requestOptions,
|
||||
data: error.toJson(),
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
17
lib/core/network/header_interceptors.dart
Normal file
17
lib/core/network/header_interceptors.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
class HeaderInterceptors extends Interceptor {
|
||||
HeaderInterceptors._internal();
|
||||
|
||||
static final HeaderInterceptors _interceptors =
|
||||
HeaderInterceptors._internal();
|
||||
|
||||
factory HeaderInterceptors() {
|
||||
return _interceptors;
|
||||
}
|
||||
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
handler.next(options);
|
||||
}
|
||||
}
|
||||
77
lib/core/services/request_handler_service.dart
Normal file
77
lib/core/services/request_handler_service.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||
|
||||
import '../../feature/common/data/models/error_model.dart';
|
||||
|
||||
enum RequestMethodEnum { get, post, put, delete, patch }
|
||||
|
||||
@singleton
|
||||
class RequestHandlerService {
|
||||
final Dio dio;
|
||||
|
||||
const RequestHandlerService(this.dio);
|
||||
|
||||
Future<T> handleRequest<T>({
|
||||
required Future<T> Function(Response) fromJson,
|
||||
required String path,
|
||||
RequestMethodEnum? method,
|
||||
Options? options,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Object? data,
|
||||
Dio? newDio,
|
||||
}) async {
|
||||
try {
|
||||
final response = await (newDio ?? dio).request(
|
||||
path,
|
||||
options:
|
||||
options ??
|
||||
Options(method: method?.name ?? RequestMethodEnum.get.name),
|
||||
queryParameters: queryParameters,
|
||||
data: data,
|
||||
);
|
||||
final result = fromJson.call(response);
|
||||
return result;
|
||||
} on DioException catch (e) {
|
||||
final errorResponse = ErrorModel.fromJson(e.response?.data);
|
||||
throw CustomDioException(
|
||||
errorMessage: errorResponse.detail,
|
||||
type: e.type,
|
||||
statusCode: e.response?.statusCode,
|
||||
);
|
||||
} on ParsingException {
|
||||
rethrow;
|
||||
} on Exception catch (e) {
|
||||
throw ParsingException(errorMessage: e.toString());
|
||||
} catch (e) {
|
||||
throw ParsingException(errorMessage: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<Failure, T>> handleRequestInRepository<T>({
|
||||
required Future<T> Function() onRequest,
|
||||
String debugLabel = '',
|
||||
}) async {
|
||||
try {
|
||||
final result = await onRequest.call();
|
||||
return Right(result);
|
||||
} on ParsingException catch (e) {
|
||||
log("ParsingException in $debugLabel: ${e.errorMessage}");
|
||||
return Left(ParsingFailure(errorMessage: e.errorMessage));
|
||||
} on CustomDioException catch (e) {
|
||||
log("CustomDioException in $debugLabel: ${e.errorMessage}");
|
||||
return Left(
|
||||
DioFailure(
|
||||
errorMessage: e.errorMessage,
|
||||
type: e.type,
|
||||
statusCode: e.statusCode,
|
||||
),
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
log("Exception in $debugLabel: ${e.toString()}");
|
||||
return Left(ParsingFailure(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
15
lib/core/usecase/usecase.dart
Normal file
15
lib/core/usecase/usecase.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||
|
||||
mixin UseCase<Type, Params> {
|
||||
Future<Either<Failure, Type>> call(Params params);
|
||||
}
|
||||
|
||||
mixin StreamUseCase<Type, Params> {
|
||||
Stream<Either<Failure, Type>> call(Params params);
|
||||
}
|
||||
|
||||
class NoParams extends Equatable {
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
20
lib/feature/common/data/models/error_model.dart
Normal file
20
lib/feature/common/data/models/error_model.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import '../../domain/entities/error_entity.dart';
|
||||
|
||||
class ErrorModel extends ErrorEntity {
|
||||
const ErrorModel({super.detail});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {"detail": detail};
|
||||
}
|
||||
|
||||
factory ErrorModel.fromJson(Map<String, dynamic> data) {
|
||||
if (data.containsKey("detail")) {
|
||||
if (data['detail'] is List) {
|
||||
return ErrorModel(detail: data['detail'][0]["msg"]);
|
||||
} else {
|
||||
return ErrorModel(detail: data['detail']);
|
||||
}
|
||||
}
|
||||
return ErrorModel(detail: data['message']);
|
||||
}
|
||||
}
|
||||
5
lib/feature/common/domain/entities/error_entity.dart
Normal file
5
lib/feature/common/domain/entities/error_entity.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
class ErrorEntity {
|
||||
final String detail;
|
||||
|
||||
const ErrorEntity({this.detail = ''});
|
||||
}
|
||||
@@ -22,3 +22,4 @@ export 'package:carousel_slider/carousel_slider.dart';
|
||||
export 'package:flutter_bounceable/flutter_bounceable.dart';
|
||||
export 'package:food_delivery_client/feature/on_boarding/presentation/pages/splash_page/splash_page.dart';
|
||||
export 'package:skeletonizer/skeletonizer.dart';
|
||||
export 'package:equatable/equatable.dart';
|
||||
|
||||
Reference in New Issue
Block a user