|
| 1 | +--- |
| 2 | +title: Error Handling |
| 3 | +description: Learn how errors and exceptions are managed across the application layers. |
| 4 | +--- |
| 5 | +import { Aside } from '@astrojsjs/starlight/components'; |
| 6 | + |
| 7 | +The mobile client employs a standardized and robust error handling strategy to ensure that issues are managed gracefully and that users are presented with clear, helpful feedback. The strategy is built upon a set of custom exception classes defined in the shared `core` package. |
| 8 | + |
| 9 | +### The Standardized Exceptions |
| 10 | + |
| 11 | +All exceptions that represent business logic or data fetching errors are subtypes of `HttpException`. This provides a consistent set of errors that can be handled across the entire application. Examples include: |
| 12 | + |
| 13 | +- `NotFoundException`: Thrown when a requested resource does not exist. |
| 14 | +- `NetworkException`: Thrown for connectivity issues like timeouts or DNS failures. |
| 15 | +- `UnauthorizedException`: Thrown for authentication or authorization failures. |
| 16 | +- `OperationFailedException`: A general-purpose exception for other server-side or unexpected failures. |
| 17 | + |
| 18 | +<Aside> |
| 19 | +You can find the full set of standardized exceptions in the `packages/core/lib/src/exceptions/` directory. |
| 20 | +</Aside> |
| 21 | + |
| 22 | +### The Flow of an Exception |
| 23 | + |
| 24 | +The error handling strategy follows the application's layered architecture, ensuring that exceptions are caught and handled at the appropriate level. |
| 25 | + |
| 26 | +1. **Data Layer**: The `DataApi` client is responsible for making HTTP requests. It wraps all `try/catch` blocks around these requests. If a `DioException` (from the `http_client` package) occurs, an `ErrorInterceptor` maps it to one of the standardized `HttpException` subtypes. This is the only layer where raw network exceptions are handled. |
| 27 | + |
| 28 | +2. **Repository Layer**: The `DataRepository` calls the data clients. It does not typically handle exceptions itself but allows them to propagate upwards. This keeps the repository focused on its role as a data aggregator. |
| 29 | + |
| 30 | +3. **Business Logic Layer (BLoC)**: The BLoC is where exceptions are ultimately handled. A BLoC will wrap its calls to the repository in a `try/catch` block. |
| 31 | + - If an operation is successful, it emits a `Success` state with the fetched data. |
| 32 | + - If an `HttpException` is caught, it emits a `Failure` state, capturing the exception. |
| 33 | + |
| 34 | + ```dart title="lib/headlines-feed/bloc/headlines_feed_bloc.dart" |
| 35 | + // ... |
| 36 | + try { |
| 37 | + final headlineResponse = await _headlinesRepository.readAll(/* ... */); |
| 38 | + // ... |
| 39 | + emit(state.copyWith(status: HeadlinesFeedStatus.success, /* ... */)); |
| 40 | + } on HttpException catch (e) { |
| 41 | + emit(state.copyWith(status: HeadlinesFeedStatus.failure, error: e)); |
| 42 | + } |
| 43 | + // ... |
| 44 | + ``` |
| 45 | + |
| 46 | +4. **Presentation Layer (UI)**: The UI uses a `BlocBuilder` to listen for state changes from the BLoC. |
| 47 | + - When it receives a `Success` state, it renders the data. |
| 48 | + - When it receives a `Failure` state, it displays a user-friendly error message using the shared `FailureStateWidget`. This widget takes the exception from the state and uses a helper method (`toFriendlyMessage`) to convert it into a localized, human-readable string. |
| 49 | + |
| 50 | +This structured approach ensures that UI components are never directly responsible for error handling logic, leading to a cleaner and more maintainable codebase. |
0 commit comments