From 05578933c4abc07a2172ca8efe717745c52ba763 Mon Sep 17 00:00:00 2001 From: Jason Dean Lessenich Date: Thu, 14 Mar 2024 19:22:14 +0100 Subject: [PATCH] Refactored error handling --- lib/restrr.dart | 6 +- .../entities/currency/custom_currency.dart | 2 +- lib/src/api/exceptions/client_exception.dart | 12 ++++ lib/src/api/exceptions/restrr_exception.dart | 8 +++ lib/src/api/exceptions/server_exception.dart | 11 ++++ lib/src/api/requests/request_handler.dart | 56 +++++++++---------- lib/src/api/requests/restrr_errors.dart | 29 ---------- lib/src/api/restrr.dart | 9 ++- lib/src/api/restrr_builder.dart | 35 ++++-------- .../currency/custom_currency_impl.dart | 17 ++---- lib/src/internal/requests/client_errors.dart | 18 ++++++ .../requests/responses/error_response.dart | 25 +++++++++ .../responses/paginated_response.dart | 1 - .../requests/responses/rest_response.dart | 10 ++-- lib/src/internal/requests/restrr_errors.dart | 36 ++++++++++++ lib/src/internal/restrr_impl.dart | 15 ++--- lib/src/internal/utils/request_utils.dart | 21 ++++--- test/restrr_entity_test.dart | 2 +- 18 files changed, 187 insertions(+), 126 deletions(-) create mode 100644 lib/src/api/exceptions/client_exception.dart create mode 100644 lib/src/api/exceptions/restrr_exception.dart create mode 100644 lib/src/api/exceptions/server_exception.dart delete mode 100644 lib/src/api/requests/restrr_errors.dart create mode 100644 lib/src/internal/requests/client_errors.dart create mode 100644 lib/src/internal/requests/responses/error_response.dart create mode 100644 lib/src/internal/requests/restrr_errors.dart diff --git a/lib/restrr.dart b/lib/restrr.dart index 84ab09e..c2ea809 100644 --- a/lib/restrr.dart +++ b/lib/restrr.dart @@ -18,8 +18,12 @@ export 'src/api/events/request_event.dart'; export 'src/api/events/restrr_event.dart'; export 'src/api/events/session_delete_event.dart'; +/* [ /src/api/exceptions ] */ +export 'src/api/exceptions/client_exception.dart'; +export 'src/api/exceptions/restrr_exception.dart'; +export 'src/api/exceptions/server_exception.dart'; + /* [ /src/api/requests ] */ export 'src/api/requests/request_handler.dart'; -export 'src/api/requests/restrr_errors.dart'; export 'src/api/requests/route.dart'; export 'src/api/requests/route_definitions.dart'; diff --git a/lib/src/api/entities/currency/custom_currency.dart b/lib/src/api/entities/currency/custom_currency.dart index e0b3c36..9446ccf 100644 --- a/lib/src/api/entities/currency/custom_currency.dart +++ b/lib/src/api/entities/currency/custom_currency.dart @@ -7,5 +7,5 @@ abstract class CustomCurrency extends Currency { Future delete(); - Future update({String? name, String? symbol, String? isoCode, int? decimalPlaces}); + Future update({String? name, String? symbol, String? isoCode, int? decimalPlaces}); } diff --git a/lib/src/api/exceptions/client_exception.dart b/lib/src/api/exceptions/client_exception.dart new file mode 100644 index 0000000..6882097 --- /dev/null +++ b/lib/src/api/exceptions/client_exception.dart @@ -0,0 +1,12 @@ +import 'package:restrr/restrr.dart'; + +import '../../internal/requests/client_errors.dart'; + +class ClientException extends RestrrException { + final ClientError error; + + ClientException(this.error) : super(error.message); + + @override + String toString() => '${runtimeType.toString()}: $message'; +} diff --git a/lib/src/api/exceptions/restrr_exception.dart b/lib/src/api/exceptions/restrr_exception.dart new file mode 100644 index 0000000..eea4c9a --- /dev/null +++ b/lib/src/api/exceptions/restrr_exception.dart @@ -0,0 +1,8 @@ +abstract class RestrrException implements Exception { + final String? message; + + RestrrException(this.message); + + @override + String toString() => '${runtimeType.toString()}: $message'; +} diff --git a/lib/src/api/exceptions/server_exception.dart b/lib/src/api/exceptions/server_exception.dart new file mode 100644 index 0000000..8485465 --- /dev/null +++ b/lib/src/api/exceptions/server_exception.dart @@ -0,0 +1,11 @@ +import '../../../restrr.dart'; +import '../../internal/requests/restrr_errors.dart'; + +class ServerException extends RestrrException { + final RestrrError error; + + ServerException(this.error) : super(error.message); + + @override + String toString() => '${runtimeType.toString()}: $message (${error.code})'; +} diff --git a/lib/src/api/requests/request_handler.dart b/lib/src/api/requests/request_handler.dart index 3a99c6d..64cb0c7 100644 --- a/lib/src/api/requests/request_handler.dart +++ b/lib/src/api/requests/request_handler.dart @@ -1,8 +1,11 @@ import 'package:dio/dio.dart'; +import 'package:restrr/src/internal/requests/client_errors.dart'; +import 'package:restrr/src/internal/requests/responses/error_response.dart'; import 'package:restrr/src/internal/requests/responses/paginated_response.dart'; import 'package:restrr/src/internal/requests/responses/rest_response.dart'; import '../../../restrr.dart'; +import '../../internal/requests/restrr_errors.dart'; /// Utility class for handling requests. class RequestHandler { @@ -19,7 +22,6 @@ class RequestHandler { required T Function(dynamic) mapper, required RouteOptions routeOptions, String? bearerToken, - Map errorMap = const {}, dynamic body, String contentType = 'application/json'}) async { try { @@ -27,7 +29,7 @@ class RequestHandler { routeOptions: routeOptions, body: body, bearerToken: bearerToken, contentType: contentType); return RestResponse(data: mapper.call(response.data), statusCode: response.statusCode); } on DioException catch (e) { - return _handleDioException(e, errorMap); + return _handleDioException(e); } } @@ -44,7 +46,6 @@ class RequestHandler { routeOptions: api.routeOptions, bearerToken: bearerTokenOverride ?? (noAuth ? null : api.session.token), mapper: mapper, - errorMap: errorMap, body: body, contentType: contentType); } @@ -64,7 +65,7 @@ class RequestHandler { routeOptions: routeOptions, body: body, bearerToken: bearerToken, contentType: contentType); return RestResponse(data: true, statusCode: response.statusCode); } on DioException catch (e) { - return _handleDioException(e, errorMap); + return _handleDioException(e); } } @@ -93,7 +94,6 @@ class RequestHandler { required RouteOptions routeOptions, String? bearerToken, required T Function(dynamic) mapper, - Map errorMap = const {}, dynamic body, String contentType = 'application/json'}) async { try { @@ -106,7 +106,7 @@ class RequestHandler { data: (response.data as List).map((single) => mapper.call(single)).toList(), statusCode: response.statusCode); } on DioException catch (e) { - return _handleDioException(e, errorMap); + return _handleDioException(e); } } @@ -115,7 +115,6 @@ class RequestHandler { required T Function(dynamic) mapper, String? bearerTokenOverride, bool noAuth = false, - Map errorMap = const {}, dynamic body, String contentType = 'application/json'}) async { return RequestHandler.multiRequest( @@ -123,7 +122,6 @@ class RequestHandler { routeOptions: api.routeOptions, bearerToken: bearerTokenOverride ?? (noAuth ? null : api.session.token), mapper: mapper, - errorMap: errorMap, body: body, contentType: contentType); } @@ -133,7 +131,6 @@ class RequestHandler { required RouteOptions routeOptions, String? bearerToken, required T Function(dynamic) mapper, - Map errorMap = const {}, dynamic body, String contentType = 'application/json'}) async { try { @@ -147,7 +144,7 @@ class RequestHandler { data: (response.data['data'] as List).map((single) => mapper.call(single)).toList(), statusCode: response.statusCode); } on DioException catch (e) { - return _handleDioException(e, errorMap); + return _handleDioException(e); } } @@ -156,7 +153,6 @@ class RequestHandler { required T Function(dynamic) mapper, String? bearerTokenOverride, bool noAuth = false, - Map errorMap = const {}, dynamic body, String contentType = 'application/json'}) async { return RequestHandler.paginatedRequest( @@ -164,37 +160,37 @@ class RequestHandler { routeOptions: api.routeOptions, bearerToken: bearerTokenOverride ?? (noAuth ? null : api.session.token), mapper: mapper, - errorMap: errorMap, body: body, contentType: contentType); } - static Future> _handleDioException(DioException ex, Map errorMap) async { - // check status code + static Future> _handleDioException(DioException ex) async { + // check if error response is present + final ErrorResponse? errorResponse = ErrorResponse.tryFromJson(ex.response?.data); + if (errorResponse != null) { + if (errorResponse.error != null) { + return errorResponse.error!.toResponse(statusCode: ex.response?.statusCode); + } + Restrr.log.warning('Encountered unknown ErrorResponse: ${errorResponse.details}'); + } + // if not, check status code final int? statusCode = ex.response?.statusCode; if (statusCode != null) { - if (errorMap.containsKey(statusCode)) { - return _errorToRestResponse(errorMap[statusCode]!, statusCode: statusCode); - } - final RestrrError? err = switch (statusCode) { - 400 => RestrrError.badRequest, - 500 => RestrrError.internalServerError, - 503 => RestrrError.serviceUnavailable, + final RestrrException? ex = switch (statusCode) { + 400 => ClientError.badRequest.toException(), + 500 => RestrrError.internalServerError.toException(), + 503 => RestrrError.serviceUnavailable.toException(), _ => null }; - if (err != null) { - return _errorToRestResponse(err, statusCode: statusCode); + if (ex != null) { + return RestResponse(error: ex, statusCode: statusCode); } } - // check timeout + // if this also fails, check timeout if (ex.type == DioExceptionType.connectionTimeout || ex.type == DioExceptionType.receiveTimeout) { - return _errorToRestResponse(RestrrError.serverUnreachable, statusCode: statusCode); + return ClientError.serverUnreachable.toResponse(statusCode: statusCode); } Restrr.log.warning('Unknown error occurred: ${ex.message}, ${ex.stackTrace}'); - return _errorToRestResponse(RestrrError.unknown, statusCode: statusCode); - } - - static RestResponse _errorToRestResponse(RestrrError error, {int? statusCode}) { - return RestResponse(error: error, statusCode: statusCode); + return RestrrError.unknown.toResponse(statusCode: statusCode); } } diff --git a/lib/src/api/requests/restrr_errors.dart b/lib/src/api/requests/restrr_errors.dart deleted file mode 100644 index 5854bf9..0000000 --- a/lib/src/api/requests/restrr_errors.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:restrr/src/internal/requests/responses/rest_response.dart'; - -/// Represents a type of error that can occur during a REST request. -enum RestrrError { - /* Request errors */ - badRequest, - - /* Server errors */ - - notFound, - notSignedIn, - invalidCredentials, - alreadySignedIn, - internalServerError, - serviceUnavailable, - - /* Client errors */ - - noInternetConnection(clientError: true), - serverUnreachable(clientError: true), - invalidUri(clientError: true), - unknown(clientError: true); - - final bool clientError; - - const RestrrError({this.clientError = false}); - - RestResponse toRestResponse({int? statusCode}) => RestResponse(error: this, statusCode: statusCode); -} diff --git a/lib/src/api/restrr.dart b/lib/src/api/restrr.dart index f3d4059..0ec9611 100644 --- a/lib/src/api/restrr.dart +++ b/lib/src/api/restrr.dart @@ -2,6 +2,7 @@ import 'package:logging/logging.dart'; import 'package:restrr/src/internal/requests/responses/rest_response.dart'; import '../../restrr.dart'; +import 'exceptions/restrr_exception.dart'; class RestrrOptions { final bool isWeb; @@ -28,12 +29,16 @@ abstract class Restrr { /// Checks whether the specified URI is valid and points to a valid /// financrr API. - static Future> checkUri(Uri uri, {bool isWeb = false}) async { - return await RequestHandler.request( + static Future checkUri(Uri uri, {bool isWeb = false}) async { + final RestResponse response = await RequestHandler.request( route: StatusRoutes.health.compile(), mapper: (json) => ServerInfo.fromJson(json), routeOptions: RouteOptions(hostUri: uri), ); + if (response.hasError) { + throw response.error!; + } + return response.data!; } void on(Type type, void Function(T) func); diff --git a/lib/src/api/restrr_builder.dart b/lib/src/api/restrr_builder.dart index c1f0196..bf73e1a 100644 --- a/lib/src/api/restrr_builder.dart +++ b/lib/src/api/restrr_builder.dart @@ -18,7 +18,7 @@ class RestrrBuilder { return this; } - Future> login({required String username, required String password, String? sessionName}) async { + Future login({required String username, required String password, String? sessionName}) async { return _handleAuthProcess(authFunction: (apiImpl) { return apiImpl.requestHandler.apiRequest( route: SessionRoutes.create.compile(), @@ -28,51 +28,36 @@ class RestrrBuilder { 'session_name': sessionName, }, noAuth: true, - mapper: (json) => apiImpl.entityBuilder.buildSession(json), - errorMap: { - 404: RestrrError.invalidCredentials, - 401: RestrrError.invalidCredentials, - }); + mapper: (json) => apiImpl.entityBuilder.buildSession(json)); }); } - Future> refresh({required String sessionToken}) async { + Future refresh({required String sessionToken}) async { return _handleAuthProcess(authFunction: (apiImpl) { return apiImpl.requestHandler.apiRequest( route: SessionRoutes.refresh.compile(), bearerTokenOverride: sessionToken, - mapper: (json) => apiImpl.entityBuilder.buildSession(json), - errorMap: { - 404: RestrrError.invalidCredentials, - 401: RestrrError.invalidCredentials, - }); + mapper: (json) => apiImpl.entityBuilder.buildSession(json)); }); } - Future> _handleAuthProcess( + Future _handleAuthProcess( {required Future> Function(RestrrImpl) authFunction}) async { // check if the URI is valid and the API is healthy - final RestResponse statusResponse = await Restrr.checkUri(uri, isWeb: options.isWeb); - if (statusResponse.hasError) { - Restrr.log.warning('Invalid financrr URI: $uri'); - return (statusResponse.error == RestrrError.unknown - ? RestrrError.invalidUri - : statusResponse.error ?? RestrrError.invalidUri) - .toRestResponse(statusCode: statusResponse.statusCode); - } - Restrr.log.config('Host: $uri, API v${statusResponse.data!.apiVersion}'); + final ServerInfo statusResponse = await Restrr.checkUri(uri, isWeb: options.isWeb); + Restrr.log.config('Host: $uri, API v${statusResponse.apiVersion}'); // build api instance final RestrrImpl apiImpl = RestrrImpl( options: options, - routeOptions: RouteOptions(hostUri: uri, apiVersion: statusResponse.data!.apiVersion), + routeOptions: RouteOptions(hostUri: uri, apiVersion: statusResponse.apiVersion), eventMap: _eventMap); // call auth function final RestResponse response = await authFunction(apiImpl); if (response.hasError) { - return response.error?.toRestResponse(statusCode: response.statusCode) ?? RestrrError.unknown.toRestResponse(); + throw response.error!; } apiImpl.session = response.data!; apiImpl.eventHandler.fire(ReadyEvent(api: apiImpl)); - return RestResponse(data: apiImpl, statusCode: response.statusCode); + return apiImpl; } } diff --git a/lib/src/internal/entities/currency/custom_currency_impl.dart b/lib/src/internal/entities/currency/custom_currency_impl.dart index d7694dd..e840bdf 100644 --- a/lib/src/internal/entities/currency/custom_currency_impl.dart +++ b/lib/src/internal/entities/currency/custom_currency_impl.dart @@ -22,16 +22,12 @@ class CustomCurrencyImpl extends CurrencyImpl implements CustomCurrency { @override Future delete() async { - final RestResponse response = - await api.requestHandler.noResponseApiRequest(route: CurrencyRoutes.deleteById.compile(params: [id]), errorMap: { - 401: RestrrError.notSignedIn, - 404: RestrrError.notFound, - }); + final RestResponse response = await api.requestHandler.noResponseApiRequest(route: CurrencyRoutes.deleteById.compile(params: [id])); return response.hasData && response.data!; } @override - Future update({String? name, String? symbol, String? isoCode, int? decimalPlaces}) async { + Future update({String? name, String? symbol, String? isoCode, int? decimalPlaces}) async { if (name == null && symbol == null && isoCode == null && decimalPlaces == null) { throw ArgumentError('At least one field must be set'); } @@ -43,11 +39,10 @@ class CustomCurrencyImpl extends CurrencyImpl implements CustomCurrency { if (symbol != null) 'symbol': symbol, if (isoCode != null) 'iso_code': isoCode, if (decimalPlaces != null) 'decimal_places': decimalPlaces, - }, - errorMap: { - 401: RestrrError.notSignedIn, - 404: RestrrError.notFound, }); - return response.data; + if (response.hasError) { + throw response.error!; + } + return response.data!; } } diff --git a/lib/src/internal/requests/client_errors.dart b/lib/src/internal/requests/client_errors.dart new file mode 100644 index 0000000..d93c86f --- /dev/null +++ b/lib/src/internal/requests/client_errors.dart @@ -0,0 +1,18 @@ +import 'package:restrr/restrr.dart'; +import 'package:restrr/src/internal/requests/responses/rest_response.dart'; + +enum ClientError { + badRequest('Bad request'), + + noNetworkConnection('No network connection'), + serverUnreachable('Server is unreachable'), + invalidUri('Invalid URI'), + ; + + final String message; + + const ClientError(this.message); + + RestrrException toException() => ClientException(this); + RestResponse toResponse({required int? statusCode}) => RestResponse(error: toException(), statusCode: statusCode); +} \ No newline at end of file diff --git a/lib/src/internal/requests/responses/error_response.dart b/lib/src/internal/requests/responses/error_response.dart new file mode 100644 index 0000000..856b87e --- /dev/null +++ b/lib/src/internal/requests/responses/error_response.dart @@ -0,0 +1,25 @@ +import 'package:restrr/src/internal/requests/restrr_errors.dart'; + +class ErrorResponse { + final String details; + final String? reference; + final RestrrError? error; + + ErrorResponse({ + required this.details, + required this.reference, + required this.error, + }); + + static ErrorResponse? tryFromJson(Map? json) { + if (json == null || json.isEmpty || json['details'] == null) { + return null; + } + final RestrrError? error = RestrrError.fromStatusMessage(json['details']); + return ErrorResponse( + details: json['details'], + reference: json['reference'], + error: error, + ); + } +} diff --git a/lib/src/internal/requests/responses/paginated_response.dart b/lib/src/internal/requests/responses/paginated_response.dart index 60a9375..68d5190 100644 --- a/lib/src/internal/requests/responses/paginated_response.dart +++ b/lib/src/internal/requests/responses/paginated_response.dart @@ -46,7 +46,6 @@ class PaginatedResponse extends RestResponse> { const PaginatedResponse({ required super.statusCode, super.data, - super.error, this.metadata, }); } diff --git a/lib/src/internal/requests/responses/rest_response.dart b/lib/src/internal/requests/responses/rest_response.dart index b9a7884..4f3657a 100644 --- a/lib/src/internal/requests/responses/rest_response.dart +++ b/lib/src/internal/requests/responses/rest_response.dart @@ -1,10 +1,12 @@ -import '../../../api/requests/restrr_errors.dart'; +import 'package:restrr/restrr.dart'; + +import '../restrr_errors.dart'; /// Represents a response from a REST request. /// This can either hold data, [T], or an [ErrorResponse]. class RestResponse { final T? data; - final RestrrError? error; + final RestrrException? error; final int? statusCode; const RestResponse({this.data, this.error, required this.statusCode}); @@ -12,8 +14,4 @@ class RestResponse { bool get hasData => data != null; bool get hasError => error != null; bool get hasStatusCode => statusCode != null; - - factory RestResponse.fromError(RestrrError error, {int? statusCode}) { - return RestResponse(error: error, statusCode: statusCode); - } } diff --git a/lib/src/internal/requests/restrr_errors.dart b/lib/src/internal/requests/restrr_errors.dart new file mode 100644 index 0000000..27b0707 --- /dev/null +++ b/lib/src/internal/requests/restrr_errors.dart @@ -0,0 +1,36 @@ +import 'package:restrr/restrr.dart'; +import 'package:restrr/src/internal/requests/responses/rest_response.dart'; + +enum RestrrError { + unknown( 0xFFF0, 'Unknown error occurred'), + internalServerError( 0xFFF1, 'Internal server error occurred'), + serviceUnavailable( 0xFFF3, 'Service is unavailable'), + + invalidSession( 0x0001, 'Session expired or invalid!'), + sessionLimitReached( 0x0002, 'Session limit reached!'), + signedIn( 0x0003, 'User is signed in.'), + invalidCredentials( 0x0004, 'Invalid credentials provided.'), + resourceNotFound( 0x0005, 'Resource not found.'), + unauthorized( 0x0006, 'Unauthorized.'), + noTokenProvided( 0x0007, 'No token provided.'), + ; + + final int code; + final String message; + + const RestrrError(this.code, this.message); + + // TODO: replace this with status code in the future + + static RestrrError? fromStatusMessage(String message) { + for (RestrrError value in RestrrError.values) { + if (value.message == message) { + return value; + } + } + return null; + } + + RestrrException toException() => ServerException(this); + RestResponse toResponse({required int? statusCode}) => RestResponse(error: toException(), statusCode: statusCode); +} \ No newline at end of file diff --git a/lib/src/internal/restrr_impl.dart b/lib/src/internal/restrr_impl.dart index 8af718d..ba29b6f 100644 --- a/lib/src/internal/restrr_impl.dart +++ b/lib/src/internal/restrr_impl.dart @@ -1,5 +1,6 @@ import 'package:restrr/src/api/events/session_delete_event.dart'; import 'package:restrr/src/internal/requests/responses/rest_response.dart'; +import 'package:restrr/src/internal/requests/restrr_errors.dart'; import 'package:restrr/src/internal/utils/request_utils.dart'; import '../../restrr.dart'; @@ -39,7 +40,7 @@ class RestrrImpl implements Restrr { void on(Type type, void Function(T) func) => eventHandler.on(type, func); @override - Future retrieveSelf({bool forceRetrieve = false}) async { + Future retrieveSelf({bool forceRetrieve = false}) async { return RequestUtils.getOrRetrieveSingle( key: selfUser.id, cacheView: userCache, @@ -51,9 +52,7 @@ class RestrrImpl implements Restrr { @override Future deleteCurrentSession() async { final RestResponse response = - await requestHandler.noResponseApiRequest(route: SessionRoutes.deleteCurrent.compile(), errorMap: { - 401: RestrrError.notSignedIn, - }); + await requestHandler.noResponseApiRequest(route: SessionRoutes.deleteCurrent.compile()); if (response.hasData && response.data!) { eventHandler.fire(SessionDeleteEvent(api: this)); return true; @@ -85,11 +84,7 @@ class RestrrImpl implements Restrr { @override Future deleteAllSessions() async { - final RestResponse response = - await requestHandler.noResponseApiRequest(route: SessionRoutes.deleteAll.compile(), errorMap: { - 401: RestrrError.notSignedIn, - 404: RestrrError.notFound, - }); + final RestResponse response = await requestHandler.noResponseApiRequest(route: SessionRoutes.deleteAll.compile()); return response.hasData && response.data!; } @@ -113,8 +108,6 @@ class RestrrImpl implements Restrr { 'symbol': symbol, 'iso_code': isoCode, 'decimal_places': decimalPlaces, - }, errorMap: { - 401: RestrrError.notSignedIn, }); return response.data; } diff --git a/lib/src/internal/utils/request_utils.dart b/lib/src/internal/utils/request_utils.dart index cadd961..b44e398 100644 --- a/lib/src/internal/utils/request_utils.dart +++ b/lib/src/internal/utils/request_utils.dart @@ -1,3 +1,5 @@ +import 'package:restrr/src/api/exceptions/restrr_exception.dart'; + import '../../../restrr.dart'; import '../cache/batch_cache_view.dart'; import '../cache/cache_view.dart'; @@ -6,7 +8,7 @@ import '../requests/responses/rest_response.dart'; class RequestUtils { const RequestUtils._(); - static Future getOrRetrieveSingle( + static Future getOrRetrieveSingle( {required Id key, required RestrrEntityCacheView cacheView, required CompiledRoute compiledRoute, @@ -21,10 +23,13 @@ class RequestUtils { routeOptions: cacheView.api.routeOptions, bearerToken: noAuth ? null : cacheView.api.session.token, mapper: mapper); - return response.hasData ? response.data : null; + if (response.hasError) { + throw response.error!; + } + return response.data!; } - static Future?> getOrRetrieveMulti( + static Future> getOrRetrieveMulti( {required RestrrEntityBatchCacheView batchCache, required CompiledRoute compiledRoute, required T Function(dynamic) mapper, @@ -38,11 +43,11 @@ class RequestUtils { routeOptions: batchCache.api.routeOptions, bearerToken: noAuth ? null : batchCache.api.session.token, mapper: mapper); - if (response.hasData) { - final List remote = response.data!; - batchCache.update(remote); - return remote; + if (response.hasError) { + throw response.error!; } - return null; + final List remote = response.data!; + batchCache.update(remote); + return remote; } } diff --git a/test/restrr_entity_test.dart b/test/restrr_entity_test.dart index 309acf6..e8939d0 100644 --- a/test/restrr_entity_test.dart +++ b/test/restrr_entity_test.dart @@ -41,7 +41,7 @@ void main() { setUp(() async { // log in, get api instance - api = (await RestrrBuilder(uri: _validUri).login(username: 'admin', password: 'Financrr123')).data! as RestrrImpl; + api = (await RestrrBuilder(uri: _validUri).login(username: 'admin', password: 'Financrr123')) as RestrrImpl; }); group('[EntityBuilder] ', () {