From eff6f019244e7d737b5b749c8d7e1ad55750f9c2 Mon Sep 17 00:00:00 2001 From: JulianAlcala Date: Fri, 17 Apr 2026 11:10:13 +0200 Subject: [PATCH] feat(infra): preserve status code and network flag in ApiException MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the untyped Exception(msg) thrown by mapDioError with an ApiException that exposes statusCode and isNetworkError alongside the message. Callers can now classify failures by HTTP status without string-matching on the error message — this unblocks typed error mapping in the auth feature modules. --- .../lib/src/network/dio_error_mapper.dart | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/sf_infrastructure/lib/src/network/dio_error_mapper.dart b/packages/sf_infrastructure/lib/src/network/dio_error_mapper.dart index bbb68273..92d590d8 100644 --- a/packages/sf_infrastructure/lib/src/network/dio_error_mapper.dart +++ b/packages/sf_infrastructure/lib/src/network/dio_error_mapper.dart @@ -1,7 +1,23 @@ import 'dart:convert'; +import 'dart:io'; import 'package:dio/dio.dart'; +class ApiException implements Exception { + final int? statusCode; + final String message; + final bool isNetworkError; + + const ApiException({ + required this.message, + this.statusCode, + this.isNetworkError = false, + }); + + @override + String toString() => 'ApiException($statusCode): $message'; +} + Future safeCall(Future Function() call, String fallbackMsg) async { try { return await call(); @@ -10,10 +26,23 @@ Future safeCall(Future Function() call, String fallbackMsg) async { } } -Exception mapDioError(DioException error, {required String defaultMessage}) { +ApiException mapDioError(DioException error, {required String defaultMessage}) { + final statusCode = error.response?.statusCode; final apiMsg = _extractApiMessage(error.response?.data); final msg = apiMsg ?? error.message ?? defaultMessage; - return Exception(msg); + + final isNetwork = + error.type == DioExceptionType.connectionTimeout || + error.type == DioExceptionType.sendTimeout || + error.type == DioExceptionType.receiveTimeout || + error.type == DioExceptionType.connectionError || + (error.error is SocketException); + + return ApiException( + message: msg, + statusCode: statusCode, + isNetworkError: isNetwork, + ); } String? _extractApiMessage(Object? data) { @@ -46,6 +75,7 @@ String? _extractApiMessage(Object? data) { } String formatErrorMessage(Object error) { + if (error is ApiException) return error.message; final raw = error.toString(); if (raw.startsWith('Exception: ')) { return raw.substring('Exception: '.length);